mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
Spin off hivex as a separate upstream project.
This commit makes the semi-independent hivex library into a separate upstream project. The git repo for hivex is now: http://git.annexia.org/?p=hivex.git;a=summary Downloads of hivex are available here: http://libguestfs.org/download/ All questions, patches, bugs etc should be sent to the libguestfs mailing list and bug tracker.
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -80,18 +80,9 @@ haskell/Guestfs010Launch
|
|||||||
haskell/Guestfs050LVCreate
|
haskell/Guestfs050LVCreate
|
||||||
haskell/Guestfs.hs
|
haskell/Guestfs.hs
|
||||||
*.hi
|
*.hi
|
||||||
hivex/*.1
|
|
||||||
hivex/*.3
|
|
||||||
hivex/hivexsh
|
|
||||||
hivex/hivexml
|
|
||||||
hivex/tools/*.opt
|
|
||||||
html/guestfish.1.html
|
html/guestfish.1.html
|
||||||
html/guestfs.3.html
|
html/guestfs.3.html
|
||||||
html/guestmount.1.html
|
html/guestmount.1.html
|
||||||
html/hivex.3.html
|
|
||||||
html/hivexget.1.html
|
|
||||||
html/hivexsh.1.html
|
|
||||||
html/hivexml.1.html
|
|
||||||
html/recipes.html
|
html/recipes.html
|
||||||
html/virt-cat.1.html
|
html/virt-cat.1.html
|
||||||
html/virt-df.1.html
|
html/virt-df.1.html
|
||||||
|
|||||||
7
HACKING
7
HACKING
@@ -92,9 +92,10 @@ fuse/
|
|||||||
haskell/
|
haskell/
|
||||||
Haskell bindings.
|
Haskell bindings.
|
||||||
|
|
||||||
hivex/
|
hivex/ [removed in 1.0.85]
|
||||||
Hive extraction library, for reading Windows Registry files.
|
This used to contain the hivex library for reading and
|
||||||
See hivex/README for more details.
|
writing Windows Registry binary hive files. This is now
|
||||||
|
available as a separate upstream project.
|
||||||
|
|
||||||
images/
|
images/
|
||||||
Some guest images to test against. These are gzipped to save
|
Some guest images to test against. These are gzipped to save
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ include $(top_srcdir)/subdir-rules.mk
|
|||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
SUBDIRS = gnulib/lib hivex src daemon appliance fish po examples images \
|
SUBDIRS = gnulib/lib src daemon appliance fish po examples images \
|
||||||
gnulib/tests capitests regressions test-tool
|
gnulib/tests capitests regressions test-tool
|
||||||
|
|
||||||
# NB: Must build inspector directory after perl and before ocaml.
|
# NB: Must build inspector directory after perl and before ocaml.
|
||||||
@@ -118,10 +118,6 @@ HTMLFILES = \
|
|||||||
html/guestfs.3.html \
|
html/guestfs.3.html \
|
||||||
html/guestfish.1.html \
|
html/guestfish.1.html \
|
||||||
html/guestmount.1.html \
|
html/guestmount.1.html \
|
||||||
html/hivex.3.html \
|
|
||||||
html/hivexget.1.html \
|
|
||||||
html/hivexml.1.html \
|
|
||||||
html/hivexsh.1.html \
|
|
||||||
html/virt-cat.1.html \
|
html/virt-cat.1.html \
|
||||||
html/virt-df.1.html \
|
html/virt-df.1.html \
|
||||||
html/virt-edit.1.html \
|
html/virt-edit.1.html \
|
||||||
|
|||||||
2
README
2
README
@@ -52,7 +52,7 @@ Requirements
|
|||||||
|
|
||||||
- genisoimage / mkisofs
|
- genisoimage / mkisofs
|
||||||
|
|
||||||
- libxml2
|
- (Optional) hivex to build Windows Registry support
|
||||||
|
|
||||||
- (Optional) FUSE to build the FUSE module
|
- (Optional) FUSE to build the FUSE module
|
||||||
|
|
||||||
|
|||||||
17
configure.ac
17
configure.ac
@@ -422,10 +422,16 @@ dnl For i18n.
|
|||||||
AM_GNU_GETTEXT([external])
|
AM_GNU_GETTEXT([external])
|
||||||
AM_GNU_GETTEXT_VERSION([0.17])
|
AM_GNU_GETTEXT_VERSION([0.17])
|
||||||
|
|
||||||
dnl libxml2 is used by the hivex library.
|
dnl hivex library (highly recommended).
|
||||||
PKG_CHECK_MODULES([LIBXML2], [libxml-2.0])
|
dnl This used to be a part of libguestfs, but was spun off into its
|
||||||
AC_SUBST([LIBXML2_CFLAGS])
|
dnl own separate upstream project in libguestfs 1.0.85.
|
||||||
AC_SUBST([LIBXML2_LIBS])
|
HAVE_HIVEX=yes
|
||||||
|
PKG_CHECK_MODULES([HIVEX], [hivex],,[
|
||||||
|
HAVE_HIVEX=no
|
||||||
|
AC_MSG_WARN([Hivex library and headers are missing, so optional Windows Registry tools won't be built])])
|
||||||
|
AM_CONDITIONAL([HAVE_HIVEX],[test "x$HAVE_HIVEX" = "xyes"])
|
||||||
|
AC_SUBST([HIVEX_CFLAGS])
|
||||||
|
AC_SUBST([HIVEX_LIBS])
|
||||||
|
|
||||||
dnl FUSE is optional to build the FUSE module.
|
dnl FUSE is optional to build the FUSE module.
|
||||||
HAVE_FUSE=yes
|
HAVE_FUSE=yes
|
||||||
@@ -736,9 +742,6 @@ AC_CONFIG_FILES([Makefile
|
|||||||
libguestfs.pc
|
libguestfs.pc
|
||||||
gnulib/lib/Makefile
|
gnulib/lib/Makefile
|
||||||
gnulib/tests/Makefile
|
gnulib/tests/Makefile
|
||||||
hivex/Makefile
|
|
||||||
hivex/t/Makefile
|
|
||||||
hivex/tools/Makefile
|
|
||||||
fuse/Makefile
|
fuse/Makefile
|
||||||
ocaml/META perl/Makefile.PL])
|
ocaml/META perl/Makefile.PL])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|||||||
506
hivex/LICENSE
506
hivex/LICENSE
@@ -1,506 +0,0 @@
|
|||||||
This is the license for the hivex library.
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 2.1, February 1999
|
|
||||||
|
|
||||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
[This is the first released version of the Lesser GPL. It also counts
|
|
||||||
as the successor of the GNU Library Public License, version 2, hence
|
|
||||||
the version number 2.1.]
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
Licenses are intended to guarantee your freedom to share and change
|
|
||||||
free software--to make sure the software is free for all its users.
|
|
||||||
|
|
||||||
This license, the Lesser General Public License, applies to some
|
|
||||||
specially designated software packages--typically libraries--of the
|
|
||||||
Free Software Foundation and other authors who decide to use it. You
|
|
||||||
can use it too, but we suggest you first think carefully about whether
|
|
||||||
this license or the ordinary General Public License is the better
|
|
||||||
strategy to use in any particular case, based on the explanations below.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom of use,
|
|
||||||
not price. Our General Public Licenses are designed to make sure that
|
|
||||||
you have the freedom to distribute copies of free software (and charge
|
|
||||||
for this service if you wish); that you receive source code or can get
|
|
||||||
it if you want it; that you can change the software and use pieces of
|
|
||||||
it in new free programs; and that you are informed that you can do
|
|
||||||
these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
distributors to deny you these rights or to ask you to surrender these
|
|
||||||
rights. These restrictions translate to certain responsibilities for
|
|
||||||
you if you distribute copies of the library or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of the library, whether gratis
|
|
||||||
or for a fee, you must give the recipients all the rights that we gave
|
|
||||||
you. You must make sure that they, too, receive or can get the source
|
|
||||||
code. If you link other code with the library, you must provide
|
|
||||||
complete object files to the recipients, so that they can relink them
|
|
||||||
with the library after making changes to the library and recompiling
|
|
||||||
it. And you must show them these terms so they know their rights.
|
|
||||||
|
|
||||||
We protect your rights with a two-step method: (1) we copyright the
|
|
||||||
library, and (2) we offer you this license, which gives you legal
|
|
||||||
permission to copy, distribute and/or modify the library.
|
|
||||||
|
|
||||||
To protect each distributor, we want to make it very clear that
|
|
||||||
there is no warranty for the free library. Also, if the library is
|
|
||||||
modified by someone else and passed on, the recipients should know
|
|
||||||
that what they have is not the original version, so that the original
|
|
||||||
author's reputation will not be affected by problems that might be
|
|
||||||
introduced by others.
|
|
||||||
|
|
||||||
Finally, software patents pose a constant threat to the existence of
|
|
||||||
any free program. We wish to make sure that a company cannot
|
|
||||||
effectively restrict the users of a free program by obtaining a
|
|
||||||
restrictive license from a patent holder. Therefore, we insist that
|
|
||||||
any patent license obtained for a version of the library must be
|
|
||||||
consistent with the full freedom of use specified in this license.
|
|
||||||
|
|
||||||
Most GNU software, including some libraries, is covered by the
|
|
||||||
ordinary GNU General Public License. This license, the GNU Lesser
|
|
||||||
General Public License, applies to certain designated libraries, and
|
|
||||||
is quite different from the ordinary General Public License. We use
|
|
||||||
this license for certain libraries in order to permit linking those
|
|
||||||
libraries into non-free programs.
|
|
||||||
|
|
||||||
When a program is linked with a library, whether statically or using
|
|
||||||
a shared library, the combination of the two is legally speaking a
|
|
||||||
combined work, a derivative of the original library. The ordinary
|
|
||||||
General Public License therefore permits such linking only if the
|
|
||||||
entire combination fits its criteria of freedom. The Lesser General
|
|
||||||
Public License permits more lax criteria for linking other code with
|
|
||||||
the library.
|
|
||||||
|
|
||||||
We call this license the "Lesser" General Public License because it
|
|
||||||
does Less to protect the user's freedom than the ordinary General
|
|
||||||
Public License. It also provides other free software developers Less
|
|
||||||
of an advantage over competing non-free programs. These disadvantages
|
|
||||||
are the reason we use the ordinary General Public License for many
|
|
||||||
libraries. However, the Lesser license provides advantages in certain
|
|
||||||
special circumstances.
|
|
||||||
|
|
||||||
For example, on rare occasions, there may be a special need to
|
|
||||||
encourage the widest possible use of a certain library, so that it becomes
|
|
||||||
a de-facto standard. To achieve this, non-free programs must be
|
|
||||||
allowed to use the library. A more frequent case is that a free
|
|
||||||
library does the same job as widely used non-free libraries. In this
|
|
||||||
case, there is little to gain by limiting the free library to free
|
|
||||||
software only, so we use the Lesser General Public License.
|
|
||||||
|
|
||||||
In other cases, permission to use a particular library in non-free
|
|
||||||
programs enables a greater number of people to use a large body of
|
|
||||||
free software. For example, permission to use the GNU C Library in
|
|
||||||
non-free programs enables many more people to use the whole GNU
|
|
||||||
operating system, as well as its variant, the GNU/Linux operating
|
|
||||||
system.
|
|
||||||
|
|
||||||
Although the Lesser General Public License is Less protective of the
|
|
||||||
users' freedom, it does ensure that the user of a program that is
|
|
||||||
linked with the Library has the freedom and the wherewithal to run
|
|
||||||
that program using a modified version of the Library.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow. Pay close attention to the difference between a
|
|
||||||
"work based on the library" and a "work that uses the library". The
|
|
||||||
former contains code derived from the library, whereas the latter must
|
|
||||||
be combined with the library in order to run.
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License Agreement applies to any software library or other
|
|
||||||
program which contains a notice placed by the copyright holder or
|
|
||||||
other authorized party saying it may be distributed under the terms of
|
|
||||||
this Lesser General Public License (also called "this License").
|
|
||||||
Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
A "library" means a collection of software functions and/or data
|
|
||||||
prepared so as to be conveniently linked with application programs
|
|
||||||
(which use some of those functions and data) to form executables.
|
|
||||||
|
|
||||||
The "Library", below, refers to any such software library or work
|
|
||||||
which has been distributed under these terms. A "work based on the
|
|
||||||
Library" means either the Library or any derivative work under
|
|
||||||
copyright law: that is to say, a work containing the Library or a
|
|
||||||
portion of it, either verbatim or with modifications and/or translated
|
|
||||||
straightforwardly into another language. (Hereinafter, translation is
|
|
||||||
included without limitation in the term "modification".)
|
|
||||||
|
|
||||||
"Source code" for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For a library, complete source code means
|
|
||||||
all the source code for all modules it contains, plus any associated
|
|
||||||
interface definition files, plus the scripts used to control compilation
|
|
||||||
and installation of the library.
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running a program using the Library is not restricted, and output from
|
|
||||||
such a program is covered only if its contents constitute a work based
|
|
||||||
on the Library (independent of the use of the Library in a tool for
|
|
||||||
writing it). Whether that is true depends on what the Library does
|
|
||||||
and what the program that uses the Library does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Library's
|
|
||||||
complete source code as you receive it, in any medium, provided that
|
|
||||||
you conspicuously and appropriately publish on each copy an
|
|
||||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
|
||||||
all the notices that refer to this License and to the absence of any
|
|
||||||
warranty; and distribute a copy of this License along with the
|
|
||||||
Library.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy,
|
|
||||||
and you may at your option offer warranty protection in exchange for a
|
|
||||||
fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Library or any portion
|
|
||||||
of it, thus forming a work based on the Library, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The modified work must itself be a software library.
|
|
||||||
|
|
||||||
b) You must cause the files modified to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
c) You must cause the whole of the work to be licensed at no
|
|
||||||
charge to all third parties under the terms of this License.
|
|
||||||
|
|
||||||
d) If a facility in the modified Library refers to a function or a
|
|
||||||
table of data to be supplied by an application program that uses
|
|
||||||
the facility, other than as an argument passed when the facility
|
|
||||||
is invoked, then you must make a good faith effort to ensure that,
|
|
||||||
in the event an application does not supply such function or
|
|
||||||
table, the facility still operates, and performs whatever part of
|
|
||||||
its purpose remains meaningful.
|
|
||||||
|
|
||||||
(For example, a function in a library to compute square roots has
|
|
||||||
a purpose that is entirely well-defined independent of the
|
|
||||||
application. Therefore, Subsection 2d requires that any
|
|
||||||
application-supplied function or table used by this function must
|
|
||||||
be optional: if the application does not supply it, the square
|
|
||||||
root function must still compute square roots.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Library,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Library, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote
|
|
||||||
it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Library.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Library
|
|
||||||
with the Library (or with a work based on the Library) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
|
||||||
License instead of this License to a given copy of the Library. To do
|
|
||||||
this, you must alter all the notices that refer to this License, so
|
|
||||||
that they refer to the ordinary GNU General Public License, version 2,
|
|
||||||
instead of to this License. (If a newer version than version 2 of the
|
|
||||||
ordinary GNU General Public License has appeared, then you can specify
|
|
||||||
that version instead if you wish.) Do not make any other change in
|
|
||||||
these notices.
|
|
||||||
|
|
||||||
Once this change is made in a given copy, it is irreversible for
|
|
||||||
that copy, so the ordinary GNU General Public License applies to all
|
|
||||||
subsequent copies and derivative works made from that copy.
|
|
||||||
|
|
||||||
This option is useful when you wish to copy part of the code of
|
|
||||||
the Library into a program that is not a library.
|
|
||||||
|
|
||||||
4. You may copy and distribute the Library (or a portion or
|
|
||||||
derivative of it, under Section 2) in object code or executable form
|
|
||||||
under the terms of Sections 1 and 2 above provided that you accompany
|
|
||||||
it with the complete corresponding machine-readable source code, which
|
|
||||||
must be distributed under the terms of Sections 1 and 2 above on a
|
|
||||||
medium customarily used for software interchange.
|
|
||||||
|
|
||||||
If distribution of object code is made by offering access to copy
|
|
||||||
from a designated place, then offering equivalent access to copy the
|
|
||||||
source code from the same place satisfies the requirement to
|
|
||||||
distribute the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
5. A program that contains no derivative of any portion of the
|
|
||||||
Library, but is designed to work with the Library by being compiled or
|
|
||||||
linked with it, is called a "work that uses the Library". Such a
|
|
||||||
work, in isolation, is not a derivative work of the Library, and
|
|
||||||
therefore falls outside the scope of this License.
|
|
||||||
|
|
||||||
However, linking a "work that uses the Library" with the Library
|
|
||||||
creates an executable that is a derivative of the Library (because it
|
|
||||||
contains portions of the Library), rather than a "work that uses the
|
|
||||||
library". The executable is therefore covered by this License.
|
|
||||||
Section 6 states terms for distribution of such executables.
|
|
||||||
|
|
||||||
When a "work that uses the Library" uses material from a header file
|
|
||||||
that is part of the Library, the object code for the work may be a
|
|
||||||
derivative work of the Library even though the source code is not.
|
|
||||||
Whether this is true is especially significant if the work can be
|
|
||||||
linked without the Library, or if the work is itself a library. The
|
|
||||||
threshold for this to be true is not precisely defined by law.
|
|
||||||
|
|
||||||
If such an object file uses only numerical parameters, data
|
|
||||||
structure layouts and accessors, and small macros and small inline
|
|
||||||
functions (ten lines or less in length), then the use of the object
|
|
||||||
file is unrestricted, regardless of whether it is legally a derivative
|
|
||||||
work. (Executables containing this object code plus portions of the
|
|
||||||
Library will still fall under Section 6.)
|
|
||||||
|
|
||||||
Otherwise, if the work is a derivative of the Library, you may
|
|
||||||
distribute the object code for the work under the terms of Section 6.
|
|
||||||
Any executables containing that work also fall under Section 6,
|
|
||||||
whether or not they are linked directly with the Library itself.
|
|
||||||
|
|
||||||
6. As an exception to the Sections above, you may also combine or
|
|
||||||
link a "work that uses the Library" with the Library to produce a
|
|
||||||
work containing portions of the Library, and distribute that work
|
|
||||||
under terms of your choice, provided that the terms permit
|
|
||||||
modification of the work for the customer's own use and reverse
|
|
||||||
engineering for debugging such modifications.
|
|
||||||
|
|
||||||
You must give prominent notice with each copy of the work that the
|
|
||||||
Library is used in it and that the Library and its use are covered by
|
|
||||||
this License. You must supply a copy of this License. If the work
|
|
||||||
during execution displays copyright notices, you must include the
|
|
||||||
copyright notice for the Library among them, as well as a reference
|
|
||||||
directing the user to the copy of this License. Also, you must do one
|
|
||||||
of these things:
|
|
||||||
|
|
||||||
a) Accompany the work with the complete corresponding
|
|
||||||
machine-readable source code for the Library including whatever
|
|
||||||
changes were used in the work (which must be distributed under
|
|
||||||
Sections 1 and 2 above); and, if the work is an executable linked
|
|
||||||
with the Library, with the complete machine-readable "work that
|
|
||||||
uses the Library", as object code and/or source code, so that the
|
|
||||||
user can modify the Library and then relink to produce a modified
|
|
||||||
executable containing the modified Library. (It is understood
|
|
||||||
that the user who changes the contents of definitions files in the
|
|
||||||
Library will not necessarily be able to recompile the application
|
|
||||||
to use the modified definitions.)
|
|
||||||
|
|
||||||
b) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (1) uses at run time a
|
|
||||||
copy of the library already present on the user's computer system,
|
|
||||||
rather than copying library functions into the executable, and (2)
|
|
||||||
will operate properly with a modified version of the library, if
|
|
||||||
the user installs one, as long as the modified version is
|
|
||||||
interface-compatible with the version that the work was made with.
|
|
||||||
|
|
||||||
c) Accompany the work with a written offer, valid for at
|
|
||||||
least three years, to give the same user the materials
|
|
||||||
specified in Subsection 6a, above, for a charge no more
|
|
||||||
than the cost of performing this distribution.
|
|
||||||
|
|
||||||
d) If distribution of the work is made by offering access to copy
|
|
||||||
from a designated place, offer equivalent access to copy the above
|
|
||||||
specified materials from the same place.
|
|
||||||
|
|
||||||
e) Verify that the user has already received a copy of these
|
|
||||||
materials or that you have already sent this user a copy.
|
|
||||||
|
|
||||||
For an executable, the required form of the "work that uses the
|
|
||||||
Library" must include any data and utility programs needed for
|
|
||||||
reproducing the executable from it. However, as a special exception,
|
|
||||||
the materials to be distributed need not include anything that is
|
|
||||||
normally distributed (in either source or binary form) with the major
|
|
||||||
components (compiler, kernel, and so on) of the operating system on
|
|
||||||
which the executable runs, unless that component itself accompanies
|
|
||||||
the executable.
|
|
||||||
|
|
||||||
It may happen that this requirement contradicts the license
|
|
||||||
restrictions of other proprietary libraries that do not normally
|
|
||||||
accompany the operating system. Such a contradiction means you cannot
|
|
||||||
use both them and the Library together in an executable that you
|
|
||||||
distribute.
|
|
||||||
|
|
||||||
7. You may place library facilities that are a work based on the
|
|
||||||
Library side-by-side in a single library together with other library
|
|
||||||
facilities not covered by this License, and distribute such a combined
|
|
||||||
library, provided that the separate distribution of the work based on
|
|
||||||
the Library and of the other library facilities is otherwise
|
|
||||||
permitted, and provided that you do these two things:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work
|
|
||||||
based on the Library, uncombined with any other library
|
|
||||||
facilities. This must be distributed under the terms of the
|
|
||||||
Sections above.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library of the fact
|
|
||||||
that part of it is a work based on the Library, and explaining
|
|
||||||
where to find the accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
8. You may not copy, modify, sublicense, link with, or distribute
|
|
||||||
the Library except as expressly provided under this License. Any
|
|
||||||
attempt otherwise to copy, modify, sublicense, link with, or
|
|
||||||
distribute the Library is void, and will automatically terminate your
|
|
||||||
rights under this License. However, parties who have received copies,
|
|
||||||
or rights, from you under this License will not have their licenses
|
|
||||||
terminated so long as such parties remain in full compliance.
|
|
||||||
|
|
||||||
9. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Library or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Library (or any work based on the
|
|
||||||
Library), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Library or works based on it.
|
|
||||||
|
|
||||||
10. Each time you redistribute the Library (or any work based on the
|
|
||||||
Library), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute, link with or modify the Library
|
|
||||||
subject to these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties with
|
|
||||||
this License.
|
|
||||||
|
|
||||||
11. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Library at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Library by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Library.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under any
|
|
||||||
particular circumstance, the balance of the section is intended to apply,
|
|
||||||
and the section as a whole is intended to apply in other circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
12. If the distribution and/or use of the Library is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Library under this License may add
|
|
||||||
an explicit geographical distribution limitation excluding those countries,
|
|
||||||
so that distribution is permitted only in or among countries not thus
|
|
||||||
excluded. In such case, this License incorporates the limitation as if
|
|
||||||
written in the body of this License.
|
|
||||||
|
|
||||||
13. The Free Software Foundation may publish revised and/or new
|
|
||||||
versions of the Lesser General Public License from time to time.
|
|
||||||
Such new versions will be similar in spirit to the present version,
|
|
||||||
but may differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Library
|
|
||||||
specifies a version number of this License which applies to it and
|
|
||||||
"any later version", you have the option of following the terms and
|
|
||||||
conditions either of that version or of any later version published by
|
|
||||||
the Free Software Foundation. If the Library does not specify a
|
|
||||||
license version number, you may choose any version ever published by
|
|
||||||
the Free Software Foundation.
|
|
||||||
|
|
||||||
14. If you wish to incorporate parts of the Library into other free
|
|
||||||
programs whose distribution conditions are incompatible with these,
|
|
||||||
write to the author to ask for permission. For software which is
|
|
||||||
copyrighted by the Free Software Foundation, write to the Free
|
|
||||||
Software Foundation; we sometimes make exceptions for this. Our
|
|
||||||
decision will be guided by the two goals of preserving the free status
|
|
||||||
of all derivatives of our free software and of promoting the sharing
|
|
||||||
and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
|
||||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
|
||||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
|
||||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
|
||||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
|
||||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
|
||||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
|
||||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
|
||||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
|
||||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
|
||||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
|
||||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
|
||||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
|
||||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|
||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Libraries
|
|
||||||
|
|
||||||
If you develop a new library, and you want it to be of the greatest
|
|
||||||
possible use to the public, we recommend making it free software that
|
|
||||||
everyone can redistribute and change. You can do so by permitting
|
|
||||||
redistribution under these terms (or, alternatively, under the terms of the
|
|
||||||
ordinary General Public License).
|
|
||||||
|
|
||||||
To apply these terms, attach the following notices to the library. It is
|
|
||||||
safest to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least the
|
|
||||||
"copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the library's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
|
||||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1990
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
That's all there is to it!
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
# libguestfs
|
|
||||||
# Copyright (C) 2009 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
SUBDIRS = t tools
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
hivex.pod \
|
|
||||||
hivexml.pod \
|
|
||||||
hivexget.pod \
|
|
||||||
hivexget \
|
|
||||||
hivexsh.pod \
|
|
||||||
LICENSE \
|
|
||||||
example1 \
|
|
||||||
example2 \
|
|
||||||
example3 \
|
|
||||||
example4 \
|
|
||||||
example5 \
|
|
||||||
example6
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libhivex.la
|
|
||||||
|
|
||||||
libhivex_la_SOURCES = \
|
|
||||||
hivex.c \
|
|
||||||
hivex.h \
|
|
||||||
byte_conversions.h
|
|
||||||
|
|
||||||
libhivex_la_LDFLAGS = -version-info 0:0:0 $(LTLIBINTL) $(LTLIBTHREAD)
|
|
||||||
libhivex_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
|
|
||||||
libhivex_la_CPPFLAGS = -I$(top_srcdir)/gnulib/lib
|
|
||||||
|
|
||||||
bin_PROGRAMS = hivexml hivexsh
|
|
||||||
bin_SCRIPTS = hivexget
|
|
||||||
noinst_SCRIPTS = example1 example2 example3 example4 example5 example6
|
|
||||||
|
|
||||||
hivexml_SOURCES = \
|
|
||||||
hivexml.c
|
|
||||||
|
|
||||||
hivexml_LDADD = libhivex.la $(LIBXML2_LIBS) ../gnulib/lib/libgnu.la
|
|
||||||
hivexml_CFLAGS = \
|
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
|
||||||
$(LIBXML2_CFLAGS) \
|
|
||||||
$(WARN_CFLAGS) $(WERROR_CFLAGS)
|
|
||||||
|
|
||||||
hivexsh_SOURCES = \
|
|
||||||
hivexsh.c \
|
|
||||||
hivex.h \
|
|
||||||
byte_conversions.h
|
|
||||||
|
|
||||||
hivexsh_LDADD = libhivex.la ../gnulib/lib/libgnu.la $(LIBREADLINE)
|
|
||||||
hivexsh_CFLAGS = \
|
|
||||||
-I$(top_srcdir)/gnulib/lib \
|
|
||||||
-I$(top_srcdir)/src \
|
|
||||||
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
|
|
||||||
$(WARN_CFLAGS) $(WERROR_CFLAGS)
|
|
||||||
|
|
||||||
man_MANS = hivex.3 hivexml.1 hivexget.1 hivexsh.1
|
|
||||||
|
|
||||||
hivex.3: hivex.pod
|
|
||||||
$(POD2MAN) \
|
|
||||||
--section 3 \
|
|
||||||
-c "Windows Registry" \
|
|
||||||
--name "hivex" \
|
|
||||||
--release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
|
|
||||||
$< > $@-t; mv $@-t $@
|
|
||||||
|
|
||||||
hivexml.1: hivexml.pod
|
|
||||||
$(POD2MAN) \
|
|
||||||
--section 1 \
|
|
||||||
-c "Windows Registry" \
|
|
||||||
--name "hivexml" \
|
|
||||||
--release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
|
|
||||||
$< > $@-t; mv $@-t $@
|
|
||||||
|
|
||||||
hivexget.1: hivexget.pod
|
|
||||||
$(POD2MAN) \
|
|
||||||
--section 1 \
|
|
||||||
-c "Windows Registry" \
|
|
||||||
--name "hivexget" \
|
|
||||||
--release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
|
|
||||||
$< > $@-t; mv $@-t $@
|
|
||||||
|
|
||||||
hivexsh.1: hivexsh.pod
|
|
||||||
$(POD2MAN) \
|
|
||||||
--section 1 \
|
|
||||||
-c "Windows Registry" \
|
|
||||||
--name "hivexsh" \
|
|
||||||
--release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
|
|
||||||
$< > $@-t; mv $@-t $@
|
|
||||||
|
|
||||||
noinst_DATA = \
|
|
||||||
$(top_builddir)/html/hivex.3.html \
|
|
||||||
$(top_builddir)/html/hivexml.1.html \
|
|
||||||
$(top_builddir)/html/hivexget.1.html \
|
|
||||||
$(top_builddir)/html/hivexsh.1.html
|
|
||||||
|
|
||||||
$(top_builddir)/html/hivex.3.html: hivex.pod
|
|
||||||
mkdir -p $(top_builddir)/html
|
|
||||||
cd $(top_builddir) && pod2html \
|
|
||||||
--css 'pod.css' \
|
|
||||||
--htmldir html \
|
|
||||||
--outfile html/hivex.3.html \
|
|
||||||
hivex/hivex.pod
|
|
||||||
|
|
||||||
$(top_builddir)/html/hivexml.1.html: hivexml.pod
|
|
||||||
mkdir -p $(top_builddir)/html
|
|
||||||
cd $(top_builddir) && pod2html \
|
|
||||||
--css 'pod.css' \
|
|
||||||
--htmldir html \
|
|
||||||
--outfile html/hivexml.1.html \
|
|
||||||
hivex/hivexml.pod
|
|
||||||
|
|
||||||
$(top_builddir)/html/hivexget.1.html: hivexget.pod
|
|
||||||
mkdir -p $(top_builddir)/html
|
|
||||||
cd $(top_builddir) && pod2html \
|
|
||||||
--css 'pod.css' \
|
|
||||||
--htmldir html \
|
|
||||||
--outfile html/hivexget.1.html \
|
|
||||||
hivex/hivexget.pod
|
|
||||||
|
|
||||||
$(top_builddir)/html/hivexsh.1.html: hivexsh.pod
|
|
||||||
mkdir -p $(top_builddir)/html
|
|
||||||
cd $(top_builddir) && pod2html \
|
|
||||||
--css 'pod.css' \
|
|
||||||
--htmldir html \
|
|
||||||
--outfile html/hivexsh.1.html \
|
|
||||||
hivex/hivexsh.pod
|
|
||||||
35
hivex/README
35
hivex/README
@@ -1,35 +0,0 @@
|
|||||||
hivex - by Richard W.M. Jones, rjones@redhat.com
|
|
||||||
Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
|
|
||||||
This is a self-contained library for reading Windows Registry "hive"
|
|
||||||
binary files.
|
|
||||||
|
|
||||||
Unlike many other tools in this area, it doesn't use the textual .REG
|
|
||||||
format for output, because parsing that is as much trouble as parsing
|
|
||||||
the original binary format. Instead it makes the file available
|
|
||||||
through a C API, or there is a separate program to export the hive as
|
|
||||||
XML.
|
|
||||||
|
|
||||||
This library was derived from several sources:
|
|
||||||
|
|
||||||
. NTREG registry reader/writer library by Petter Nordahl-Hagen
|
|
||||||
(LGPL v2.1 licensed library and program)
|
|
||||||
. http://pogostick.net/~pnh/ntpasswd/WinReg.txt
|
|
||||||
. dumphive (a BSD-licensed Pascal program by Markus Stephany)
|
|
||||||
. http://www.sentinelchicken.com/data/TheWindowsNTRegistryFileFormat.pdf
|
|
||||||
. editreg program from Samba - this program was removed in later
|
|
||||||
versions of Samba, so you have to go back in the source repository
|
|
||||||
to find it (GPLv2+)
|
|
||||||
. http://amnesia.gtisc.gatech.edu/~moyix/suzibandit.ltd.uk/MSc/
|
|
||||||
. reverse engineering the format (see hivex/tools/visualizer.ml)
|
|
||||||
|
|
||||||
Like NTREG, this library only attempts to read Windows NT registry
|
|
||||||
files (ie. not Windows 3.1 or Windows 95/98/ME). See the link above
|
|
||||||
for documentation on the older formats if you wish to read them.
|
|
||||||
|
|
||||||
Unlike NTREG, this code is much more careful about handling error
|
|
||||||
cases, corrupt and malicious registry files, and endianness.
|
|
||||||
|
|
||||||
The license for this library is LGPL v2.1, but not later versions.
|
|
||||||
For full details, see the file LICENSE in this directory.
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
/* Useful byte conversion macros, not available on all platforms.
|
|
||||||
* Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation;
|
|
||||||
* version 2.1 of the License.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef hivex_byteorder_h
|
|
||||||
#define hivex_byteorder_h
|
|
||||||
|
|
||||||
#ifdef HAVE_ENDIAN_H
|
|
||||||
#include <endian.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_BYTESWAP_H
|
|
||||||
#include <byteswap.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
#ifndef be32toh
|
|
||||||
#define be32toh(x) __bswap_32 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htobe32
|
|
||||||
#define htobe32(x) __bswap_32 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef be64toh
|
|
||||||
#define be64toh(x) __bswap_64 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htobe64
|
|
||||||
#define htobe64(x) __bswap_64 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le16toh
|
|
||||||
#define le16toh(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole16
|
|
||||||
#define htole16(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le32toh
|
|
||||||
#define le32toh(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole32
|
|
||||||
#define htole32(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le64toh
|
|
||||||
#define le64toh(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole64
|
|
||||||
#define htole64(x) (x)
|
|
||||||
#endif
|
|
||||||
#else /* __BYTE_ORDER == __BIG_ENDIAN */
|
|
||||||
#ifndef be32toh
|
|
||||||
#define be32toh(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htobe32
|
|
||||||
#define htobe32(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef be64toh
|
|
||||||
#define be64toh(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htobe64
|
|
||||||
#define htobe64(x) (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le16toh
|
|
||||||
#define le16toh(x) __bswap_16 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole16
|
|
||||||
#define htole16(x) __bswap_16 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le32toh
|
|
||||||
#define le32toh(x) __bswap_32 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole32
|
|
||||||
#define htole32(x) __bswap_32 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef le64toh
|
|
||||||
#define le64toh(x) __bswap_64 (x)
|
|
||||||
#endif
|
|
||||||
#ifndef htole64
|
|
||||||
#define htole64(x) __bswap_64 (x)
|
|
||||||
#endif
|
|
||||||
#endif /* __BYTE_ORDER == __BIG_ENDIAN */
|
|
||||||
|
|
||||||
#endif /* hivex_byteorder_h */
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Example program which loads and saves a hive.
|
|
||||||
#
|
|
||||||
# The intention of this example is just to check that we can do this
|
|
||||||
# without corrupting the hive (header etc).
|
|
||||||
#
|
|
||||||
# NB: The copy of the hive will not be absolutely identical. The
|
|
||||||
# sequence numbers in the header will change. If we implement the
|
|
||||||
# last modified field in the header, then that and the checksum will
|
|
||||||
# also change.
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "$0 input output"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $1
|
|
||||||
commit $2
|
|
||||||
EOF
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Example program which modifies a hive.
|
|
||||||
#
|
|
||||||
# This program removes any existing (key, value) pairs at the root
|
|
||||||
# node and replaces them with some example values.
|
|
||||||
#
|
|
||||||
# You can load the modified hive using another tool to see the
|
|
||||||
# changes. eg. Using Windows regedit, select HKLM and then in the
|
|
||||||
# File menu choose "Load Hive ...". Point to the update hive, and
|
|
||||||
# then give a key (eg. "test1"). The modified hive will be loaded
|
|
||||||
# under HKLM\test1 and the values can be inspected there. After
|
|
||||||
# inspecting the changes, unload the hive using File -> Unload Hive.
|
|
||||||
#
|
|
||||||
# Don't replace the original Windows hive, else you'll break things :-)
|
|
||||||
|
|
||||||
if [ $# -ne 0 ]; then
|
|
||||||
echo "$0: no arguments required"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $d/t/minimal
|
|
||||||
setval 1
|
|
||||||
@
|
|
||||||
string:Root
|
|
||||||
commit /tmp/modified
|
|
||||||
EOF
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Example program which modifies a hive.
|
|
||||||
#
|
|
||||||
# This program removes any existing (key, value) pairs at the root
|
|
||||||
# node and replaces them with some example values.
|
|
||||||
#
|
|
||||||
# You can load the modified hive using another tool to see the
|
|
||||||
# changes. eg. Using Windows regedit, select HKLM and then in the
|
|
||||||
# File menu choose "Load Hive ...". Point to the update hive, and
|
|
||||||
# then give a key (eg. "test1"). The modified hive will be loaded
|
|
||||||
# under HKLM\test1 and the values can be inspected there. After
|
|
||||||
# inspecting the changes, unload the hive using File -> Unload Hive.
|
|
||||||
#
|
|
||||||
# Don't replace the original Windows hive, else you'll break things :-)
|
|
||||||
|
|
||||||
if [ $# -ne 0 ]; then
|
|
||||||
echo "$0: no arguments required"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $d/t/minimal
|
|
||||||
setval 4
|
|
||||||
@
|
|
||||||
string:Root
|
|
||||||
A
|
|
||||||
string:abcd
|
|
||||||
B
|
|
||||||
dword:0x12345678
|
|
||||||
C
|
|
||||||
string:dcbadcbadcbaabcd
|
|
||||||
commit /tmp/modified
|
|
||||||
EOF
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# This program deletes the whole \Microsoft tree from a software hive.
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "$0 software software.new"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $1
|
|
||||||
cd \Microsoft
|
|
||||||
del
|
|
||||||
commit $2
|
|
||||||
EOF
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# This script adds a new node under \Microsoft in an existing software
|
|
||||||
# hive.
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "$0 software software.new"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $1
|
|
||||||
cd \Microsoft
|
|
||||||
add TestNode
|
|
||||||
cd TestNode
|
|
||||||
add Test1
|
|
||||||
add Test2
|
|
||||||
add Test3
|
|
||||||
add Test4
|
|
||||||
add Test5
|
|
||||||
cd Test1
|
|
||||||
setval 2
|
|
||||||
@
|
|
||||||
string:This is the default key of Test1
|
|
||||||
ThisIsTest1
|
|
||||||
dword:0x12345678
|
|
||||||
cd ..
|
|
||||||
cd Test5
|
|
||||||
setval 2
|
|
||||||
@
|
|
||||||
string:This is the default key of Test5
|
|
||||||
ThisIsTest5
|
|
||||||
dword:0x87654321
|
|
||||||
commit $2
|
|
||||||
EOF
|
|
||||||
126
hivex/example6
126
hivex/example6
@@ -1,126 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Hypothetical viostor installation in a W2K3 system registry.
|
|
||||||
|
|
||||||
if [ $# -ne 2 ]; then
|
|
||||||
echo "$0 system system.new"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
d=`dirname $0`
|
|
||||||
|
|
||||||
$d/hivexsh -w <<EOF
|
|
||||||
load $1
|
|
||||||
|
|
||||||
cd \ControlSet001\Control\CriticalDeviceDatabase
|
|
||||||
|
|
||||||
add pci#ven_1af4&dev_1001&subsys_00000000
|
|
||||||
cd pci#ven_1af4&dev_1001&subsys_00000000
|
|
||||||
setval 2
|
|
||||||
Service
|
|
||||||
string:viostor
|
|
||||||
ClassGUID
|
|
||||||
string:{4D36E97B-E325-11CE-BFC1-08002BE10318}
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
add pci#ven_1af4&dev_1001&subsys_00020000
|
|
||||||
cd pci#ven_1af4&dev_1001&subsys_00020000
|
|
||||||
setval 2
|
|
||||||
Service
|
|
||||||
string:viostor
|
|
||||||
ClassGUID
|
|
||||||
string:{4D36E97B-E325-11CE-BFC1-08002BE10318}
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
add pci#ven_1af4&dev_1001&subsys_00021af4
|
|
||||||
cd pci#ven_1af4&dev_1001&subsys_00021af4
|
|
||||||
setval 2
|
|
||||||
Service
|
|
||||||
string:viostor
|
|
||||||
ClassGUID
|
|
||||||
string:{4D36E97B-E325-11CE-BFC1-08002BE10318}
|
|
||||||
|
|
||||||
cd \ControlSet001\Services
|
|
||||||
add viostor
|
|
||||||
cd viostor
|
|
||||||
setval 6
|
|
||||||
Type
|
|
||||||
dword:0x00000001
|
|
||||||
Start
|
|
||||||
dword:0x00000000
|
|
||||||
Group
|
|
||||||
string:SCSI miniport
|
|
||||||
ErrorControl
|
|
||||||
dword:0x00000001
|
|
||||||
ImagePath
|
|
||||||
string:system32\drivers\viostor.sys
|
|
||||||
Tag
|
|
||||||
dword:0x00000021
|
|
||||||
|
|
||||||
add Parameters
|
|
||||||
cd Parameters
|
|
||||||
setval 1
|
|
||||||
BusType
|
|
||||||
dword:0x00000001
|
|
||||||
|
|
||||||
add MaxTransferSize
|
|
||||||
cd MaxTransferSize
|
|
||||||
setval 3
|
|
||||||
ParamDesc
|
|
||||||
string:Maximum Transfer Size
|
|
||||||
type
|
|
||||||
string:enum
|
|
||||||
default
|
|
||||||
string:0
|
|
||||||
|
|
||||||
add enum
|
|
||||||
cd enum
|
|
||||||
setval 3
|
|
||||||
0
|
|
||||||
string:64 KB
|
|
||||||
1
|
|
||||||
string:128 KB
|
|
||||||
2
|
|
||||||
string:256 KB
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
add PnpInterface
|
|
||||||
cd PnpInterface
|
|
||||||
setval 1
|
|
||||||
5
|
|
||||||
dword:0x00000001
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
add Enum
|
|
||||||
cd Enum
|
|
||||||
setval 3
|
|
||||||
0
|
|
||||||
string:PCI\VEN_1AF4&DEV_1001&SUBSYS_00021AF4&REV_00\3&13c0b0c5&0&20
|
|
||||||
Count
|
|
||||||
dword:0x00000001
|
|
||||||
NextInstance
|
|
||||||
dword:0x00000001
|
|
||||||
|
|
||||||
commit $2
|
|
||||||
EOF
|
|
||||||
2557
hivex/hivex.c
2557
hivex/hivex.c
File diff suppressed because it is too large
Load Diff
131
hivex/hivex.h
131
hivex/hivex.h
@@ -1,131 +0,0 @@
|
|||||||
/* hivex - Windows Registry "hive" extraction library.
|
|
||||||
* Copyright (C) 2009 Red Hat Inc.
|
|
||||||
* Derived from code by Petter Nordahl-Hagen under a compatible license:
|
|
||||||
* Copyright (c) 1997-2007 Petter Nordahl-Hagen.
|
|
||||||
* Derived from code by Markus Stephany under a compatible license:
|
|
||||||
* Copyright (c)2000-2004, Markus Stephany.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation;
|
|
||||||
* version 2.1 of the License.
|
|
||||||
*
|
|
||||||
* This library 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
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* See file LICENSE for the full license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef HIVEX_H_
|
|
||||||
#define HIVEX_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* NOTE: This API is documented in the man page hivex(3). */
|
|
||||||
|
|
||||||
typedef struct hive_h hive_h;
|
|
||||||
typedef size_t hive_node_h;
|
|
||||||
typedef size_t hive_value_h;
|
|
||||||
|
|
||||||
enum hive_type {
|
|
||||||
/* Just a key without a value. */
|
|
||||||
hive_t_none = 0,
|
|
||||||
|
|
||||||
/* A UTF-16 Windows string. */
|
|
||||||
hive_t_string = 1,
|
|
||||||
|
|
||||||
/* A UTF-16 Windows string that contains %env% (environment variable
|
|
||||||
* substitutions).
|
|
||||||
*/
|
|
||||||
hive_t_expand_string = 2,
|
|
||||||
|
|
||||||
/* A blob of binary. */
|
|
||||||
hive_t_binary = 3,
|
|
||||||
|
|
||||||
/* Two ways to encode DWORDs (32 bit words). The first is little-endian. */
|
|
||||||
hive_t_dword = 4,
|
|
||||||
hive_t_dword_be = 5,
|
|
||||||
|
|
||||||
/* Symbolic link, we think to another part of the registry tree. */
|
|
||||||
hive_t_link = 6,
|
|
||||||
|
|
||||||
/* Multiple UTF-16 Windows strings, each separated by zero byte. See:
|
|
||||||
* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx
|
|
||||||
*/
|
|
||||||
hive_t_multiple_strings = 7,
|
|
||||||
|
|
||||||
/* These three are unknown. */
|
|
||||||
hive_t_resource_list = 8,
|
|
||||||
hive_t_full_resource_description = 9,
|
|
||||||
hive_t_resource_requirements_list = 10,
|
|
||||||
|
|
||||||
/* A QWORD (64 bit word). This is stored in the file little-endian. */
|
|
||||||
hive_t_qword = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum hive_type hive_type;
|
|
||||||
|
|
||||||
/* Bitmask of flags passed to hivex_open. */
|
|
||||||
#define HIVEX_OPEN_VERBOSE 1
|
|
||||||
#define HIVEX_OPEN_DEBUG 2
|
|
||||||
#define HIVEX_OPEN_MSGLVL_MASK (HIVEX_OPEN_VERBOSE|HIVEX_OPEN_DEBUG)
|
|
||||||
#define HIVEX_OPEN_WRITE 4
|
|
||||||
|
|
||||||
extern hive_h *hivex_open (const char *filename, int flags);
|
|
||||||
extern int hivex_close (hive_h *h);
|
|
||||||
extern hive_node_h hivex_root (hive_h *h);
|
|
||||||
extern char *hivex_node_name (hive_h *h, hive_node_h node);
|
|
||||||
extern hive_node_h *hivex_node_children (hive_h *h, hive_node_h node);
|
|
||||||
extern hive_node_h hivex_node_get_child (hive_h *h, hive_node_h node, const char *name);
|
|
||||||
extern hive_node_h hivex_node_parent (hive_h *h, hive_node_h node);
|
|
||||||
extern hive_value_h *hivex_node_values (hive_h *h, hive_node_h node);
|
|
||||||
extern hive_value_h hivex_node_get_value (hive_h *h, hive_node_h node, const char *key);
|
|
||||||
extern char *hivex_value_key (hive_h *h, hive_value_h value);
|
|
||||||
extern int hivex_value_type (hive_h *h, hive_value_h value, hive_type *t, size_t *len);
|
|
||||||
extern char *hivex_value_value (hive_h *h, hive_value_h value, hive_type *t, size_t *len);
|
|
||||||
extern char *hivex_value_string (hive_h *h, hive_value_h value);
|
|
||||||
extern char **hivex_value_multiple_strings (hive_h *h, hive_value_h value);
|
|
||||||
extern int32_t hivex_value_dword (hive_h *h, hive_value_h value);
|
|
||||||
extern int64_t hivex_value_qword (hive_h *h, hive_value_h value);
|
|
||||||
struct hivex_visitor {
|
|
||||||
int (*node_start) (hive_h *, void *opaque, hive_node_h, const char *name);
|
|
||||||
int (*node_end) (hive_h *, void *opaque, hive_node_h, const char *name);
|
|
||||||
int (*value_string) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
|
|
||||||
int (*value_multiple_strings) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
|
|
||||||
int (*value_string_invalid_utf16) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
|
|
||||||
int (*value_dword) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
|
|
||||||
int (*value_qword) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
|
|
||||||
int (*value_binary) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
int (*value_none) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
int (*value_other) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
int (*value_any) (hive_h *, void *opaque, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HIVEX_VISIT_SKIP_BAD 1
|
|
||||||
|
|
||||||
extern int hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
|
|
||||||
extern int hivex_visit_node (hive_h *h, hive_node_h node, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
|
|
||||||
|
|
||||||
extern int hivex_commit (hive_h *h, const char *filename, int flags);
|
|
||||||
extern hive_node_h hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name);
|
|
||||||
extern int hivex_node_delete_child (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
struct hive_set_value {
|
|
||||||
char *key;
|
|
||||||
hive_type t;
|
|
||||||
size_t len;
|
|
||||||
char *value;
|
|
||||||
};
|
|
||||||
typedef struct hive_set_value hive_set_value;
|
|
||||||
|
|
||||||
extern int hivex_node_set_values (hive_h *h, hive_node_h node, size_t nr_values, const hive_set_value *values, int flags);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* HIVEX_H_ */
|
|
||||||
655
hivex/hivex.pod
655
hivex/hivex.pod
@@ -1,655 +0,0 @@
|
|||||||
=encoding utf8
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
hivex - Windows Registry "hive" extraction library
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
hive_h *hivex_open (const char *filename, int flags);
|
|
||||||
int hivex_close (hive_h *h);
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
libhivex is a library for extracting the contents of Windows Registry
|
|
||||||
"hive" files. It is designed to be secure against buggy or malicious
|
|
||||||
registry files.
|
|
||||||
|
|
||||||
Unlike many other tools in this area, it doesn't use the textual .REG
|
|
||||||
format for output, because parsing that is as much trouble as parsing
|
|
||||||
the original binary format. Instead it makes the file available
|
|
||||||
through a C API, or there is a separate program to export the hive as
|
|
||||||
XML (see L<hivexml(1)>), or to get individual keys (see
|
|
||||||
L<hivexget(1)>).
|
|
||||||
|
|
||||||
=head2 OPENING AND CLOSING A HIVE
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item hive_h *hivex_open (const char *filename, int flags);
|
|
||||||
|
|
||||||
Opens the hive named C<filename> for reading.
|
|
||||||
|
|
||||||
Flags is an ORed list of the open flags (or C<0> if you don't
|
|
||||||
want to pass any flags). These flags are defined:
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item HIVEX_OPEN_VERBOSE
|
|
||||||
|
|
||||||
Verbose messages.
|
|
||||||
|
|
||||||
=item HIVEX_OPEN_DEBUG
|
|
||||||
|
|
||||||
Very verbose messages, suitable for debugging problems in the library
|
|
||||||
itself.
|
|
||||||
|
|
||||||
This is also selected if the C<HIVEX_DEBUG> environment variable
|
|
||||||
is set to 1.
|
|
||||||
|
|
||||||
=item HIVEX_OPEN_WRITE
|
|
||||||
|
|
||||||
Open the hive for writing. If omitted, the hive is read-only.
|
|
||||||
|
|
||||||
See L</WRITING TO HIVE FILES>.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
C<hivex_open> returns a hive handle. On error this returns NULL and
|
|
||||||
sets C<errno> to indicate the error.
|
|
||||||
|
|
||||||
=item int hivex_close (hive_h *h);
|
|
||||||
|
|
||||||
Close a hive handle and free all associated resources.
|
|
||||||
|
|
||||||
Note that any uncommitted writes are I<not> committed by this call,
|
|
||||||
but instead are lost. See L</WRITING TO HIVE FILES>.
|
|
||||||
|
|
||||||
Returns 0 on success. On error this returns -1 and sets errno.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 NAVIGATING THE TREE OF HIVE SUBKEYS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item hive_node_h
|
|
||||||
|
|
||||||
This is a node handle, an integer but opaque outside the library.
|
|
||||||
Valid node handles cannot be 0. The library returns 0 in some
|
|
||||||
situations to indicate an error.
|
|
||||||
|
|
||||||
=item hive_node_h hivex_root (hive_h *h);
|
|
||||||
|
|
||||||
Return root node of the hive. All valid registries must contain
|
|
||||||
a root node.
|
|
||||||
|
|
||||||
On error this returns 0 and sets errno.
|
|
||||||
|
|
||||||
=item char *hivex_node_name (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
Return the name of the node. The name is reencoded as UTF-8
|
|
||||||
and returned as a C string.
|
|
||||||
|
|
||||||
The string should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
Note that the name of the root node is a dummy, such as
|
|
||||||
C<$$$PROTO.HIV> (other names are possible: it seems to depend on the
|
|
||||||
tool or program that created the hive in the first place). You can
|
|
||||||
only know the "real" name of the root node by knowing which registry
|
|
||||||
file this hive originally comes from, which is knowledge that is
|
|
||||||
outside the scope of this library.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item hive_node_h *hivex_node_children (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
Return a 0-terminated array of nodes which are the subkeys
|
|
||||||
(children) of C<node>.
|
|
||||||
|
|
||||||
The array should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item hive_node_h hivex_node_get_child (hive_h *h, hive_node_h node, const char *name);
|
|
||||||
|
|
||||||
Return the child of node with the name C<name>, if it exists.
|
|
||||||
|
|
||||||
The name is matched case insensitively.
|
|
||||||
|
|
||||||
If the child node does not exist, this returns 0 without
|
|
||||||
setting errno.
|
|
||||||
|
|
||||||
On error this returns 0 and sets errno.
|
|
||||||
|
|
||||||
=item hive_node_h hivex_node_parent (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
Return the parent of C<node>.
|
|
||||||
|
|
||||||
On error this returns 0 and sets errno.
|
|
||||||
|
|
||||||
The parent pointer of the root node in registry files that we
|
|
||||||
have examined seems to be invalid, and so this function will
|
|
||||||
return an error if called on the root node.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 GETTING VALUES AT A NODE
|
|
||||||
|
|
||||||
The enum below describes the possible types for the value(s)
|
|
||||||
stored at each node.
|
|
||||||
|
|
||||||
enum hive_type {
|
|
||||||
hive_t_none = 0,
|
|
||||||
hive_t_string = 1,
|
|
||||||
hive_t_expand_string = 2,
|
|
||||||
hive_t_binary = 3,
|
|
||||||
hive_t_dword = 4,
|
|
||||||
hive_t_dword_be = 5,
|
|
||||||
hive_t_link = 6,
|
|
||||||
hive_t_multiple_strings = 7,
|
|
||||||
hive_t_resource_list = 8,
|
|
||||||
hive_t_full_resource_description = 9,
|
|
||||||
hive_t_resource_requirements_list = 10,
|
|
||||||
hive_t_qword = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item hive_value_h
|
|
||||||
|
|
||||||
This is a value handle, an integer but opaque outside the library.
|
|
||||||
Valid value handles cannot be 0. The library returns 0 in some
|
|
||||||
situations to indicate an error.
|
|
||||||
|
|
||||||
=item hive_value_h *hivex_node_values (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
Return the 0-terminated array of (key, value) pairs attached to
|
|
||||||
this node.
|
|
||||||
|
|
||||||
The array should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item hive_value_h hivex_node_get_value (hive_h *h, hive_node_h node, const char *key);
|
|
||||||
|
|
||||||
Return the value attached to this node which has the name C<key>,
|
|
||||||
if it exists.
|
|
||||||
|
|
||||||
The key name is matched case insensitively.
|
|
||||||
|
|
||||||
Note that to get the default key, you should pass the empty
|
|
||||||
string C<""> here. The default key is often written C<"@">, but
|
|
||||||
inside hives that has no meaning and won't give you the
|
|
||||||
default key.
|
|
||||||
|
|
||||||
If no such key exists, this returns 0 and does not set errno.
|
|
||||||
|
|
||||||
On error this returns 0 and sets errno.
|
|
||||||
|
|
||||||
=item char *hivex_value_key (hive_h *h, hive_value_h value);
|
|
||||||
|
|
||||||
Return the key (name) of a (key, value) pair. The name
|
|
||||||
is reencoded as UTF-8 and returned as a C string.
|
|
||||||
|
|
||||||
The string should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
Note that this function can return a zero-length string. In the
|
|
||||||
context of Windows Registries, this means that this value is the
|
|
||||||
default key for this node in the tree. This is usually written
|
|
||||||
as C<"@">.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item int hivex_value_type (hive_h *h, hive_value_h value, hive_type *t, size_t *len);
|
|
||||||
|
|
||||||
Return the data type and length of the value in this (key, value)
|
|
||||||
pair. See also C<hivex_value_value> which returns all this
|
|
||||||
information, and the value itself. Also, C<hivex_value_*> functions
|
|
||||||
below which can be used to return the value in a more useful form when
|
|
||||||
you know the type in advance.
|
|
||||||
|
|
||||||
Returns 0 on success. On error this returns -1 and sets errno.
|
|
||||||
|
|
||||||
=item char *hivex_value_value (hive_h *h, hive_value_h value, hive_type *t, size_t *len);
|
|
||||||
|
|
||||||
Return the value of this (key, value) pair. The value should
|
|
||||||
be interpreted according to its type (see C<enum hive_type>).
|
|
||||||
|
|
||||||
The value is returned in an array of bytes of length C<len>.
|
|
||||||
|
|
||||||
The value should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item char *hivex_value_string (hive_h *h, hive_value_h value);
|
|
||||||
|
|
||||||
If this value is a string, return the string reencoded as UTF-8
|
|
||||||
(as a C string). This only works for values which have type
|
|
||||||
C<hive_t_string>, C<hive_t_expand_string> or C<hive_t_link>.
|
|
||||||
|
|
||||||
The string should be freed by the caller when it is no longer needed.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item char **hivex_value_multiple_strings (hive_h *h, hive_value_h value);
|
|
||||||
|
|
||||||
If this value is a multiple-string, return the strings reencoded
|
|
||||||
as UTF-8 (as a NULL-terminated array of C strings). This only
|
|
||||||
works for values which have type C<hive_t_multiple_strings>.
|
|
||||||
|
|
||||||
The string array and each string in it should be freed by the
|
|
||||||
caller when they are no longer needed.
|
|
||||||
|
|
||||||
On error this returns NULL and sets errno.
|
|
||||||
|
|
||||||
=item int32_t hivex_value_dword (hive_h *h, hive_value_h value);
|
|
||||||
|
|
||||||
If this value is a DWORD (Windows int32), return it. This only works
|
|
||||||
for values which have type C<hive_t_dword> or C<hive_t_dword_be>.
|
|
||||||
|
|
||||||
=item int64_t hivex_value_qword (hive_h *h, hive_value_h value);
|
|
||||||
|
|
||||||
If this value is a QWORD (Windows int64), return it. This only
|
|
||||||
works for values which have type C<hive_t_qword>.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 VISITING ALL NODES
|
|
||||||
|
|
||||||
The visitor pattern is useful if you want to visit all nodes
|
|
||||||
in the tree or all nodes below a certain point in the tree.
|
|
||||||
|
|
||||||
First you set up your own C<struct hivex_visitor> with your
|
|
||||||
callback functions.
|
|
||||||
|
|
||||||
Each of these callback functions should return 0 on success or -1
|
|
||||||
on error. If any callback returns -1, then the entire visit
|
|
||||||
terminates immediately. If you don't need a callback function at
|
|
||||||
all, set the function pointer to NULL.
|
|
||||||
|
|
||||||
struct hivex_visitor {
|
|
||||||
int (*node_start) (hive_h *, void *opaque, hive_node_h, const char *name);
|
|
||||||
int (*node_end) (hive_h *, void *opaque, hive_node_h, const char *name);
|
|
||||||
int (*value_string) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, const char *str);
|
|
||||||
int (*value_multiple_strings) (hive_h *, void *opaque, hive_node_h,
|
|
||||||
hive_value_h, hive_type t, size_t len, const char *key, char **argv);
|
|
||||||
int (*value_string_invalid_utf16) (hive_h *, void *opaque, hive_node_h,
|
|
||||||
hive_value_h, hive_type t, size_t len, const char *key,
|
|
||||||
const char *str);
|
|
||||||
int (*value_dword) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, int32_t);
|
|
||||||
int (*value_qword) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, int64_t);
|
|
||||||
int (*value_binary) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
int (*value_none) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
int (*value_other) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
/* If value_any callback is not NULL, then the other value_*
|
|
||||||
* callbacks are not used, and value_any is called on all values.
|
|
||||||
*/
|
|
||||||
int (*value_any) (hive_h *, void *opaque, hive_node_h, hive_value_h,
|
|
||||||
hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
};
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item int hivex_visit (hive_h *h, const struct hivex_visitor *visitor, size_t len, void *opaque, int flags);
|
|
||||||
|
|
||||||
Visit all the nodes recursively in the hive C<h>.
|
|
||||||
|
|
||||||
C<visitor> should be a C<hivex_visitor> structure with callback
|
|
||||||
fields filled in as required (unwanted callbacks can be set to
|
|
||||||
NULL). C<len> must be the length of the 'visitor' struct (you
|
|
||||||
should pass C<sizeof (struct hivex_visitor)> for this).
|
|
||||||
|
|
||||||
This returns 0 if the whole recursive visit was completed
|
|
||||||
successfully. On error this returns -1. If one of the callback
|
|
||||||
functions returned an error than we don't touch errno. If the
|
|
||||||
error was generated internally then we set errno.
|
|
||||||
|
|
||||||
You can skip bad registry entries by setting C<flag> to
|
|
||||||
C<HIVEX_VISIT_SKIP_BAD>. If this flag is not set, then a bad registry
|
|
||||||
causes the function to return an error immediately.
|
|
||||||
|
|
||||||
This function is robust if the registry contains cycles or
|
|
||||||
pointers which are invalid or outside the registry. It detects
|
|
||||||
these cases and returns an error.
|
|
||||||
|
|
||||||
=item int hivex_visit_node (hive_h *h, hive_node_h node, const struct hivex_visitor *visitor, size_t len, void *opaque);
|
|
||||||
|
|
||||||
Same as C<hivex_visit> but instead of starting out at the root, this
|
|
||||||
starts at C<node>.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 WRITING TO HIVE FILES
|
|
||||||
|
|
||||||
The hivex library supports making limited modifications to hive files.
|
|
||||||
We have tried to implement this very conservatively in order to reduce
|
|
||||||
the chance of corrupting your registry. However you should be careful
|
|
||||||
and take back-ups, since Microsoft has never documented the hive
|
|
||||||
format, and so it is possible there are nuances in the
|
|
||||||
reverse-engineered format that we do not understand.
|
|
||||||
|
|
||||||
To be able to modify a hive, you must pass the C<HIVEX_OPEN_WRITE>
|
|
||||||
flag to C<hivex_open>, otherwise any write operation will return with
|
|
||||||
errno C<EROFS>.
|
|
||||||
|
|
||||||
The write operations shown below do not modify the on-disk file
|
|
||||||
immediately. You must call C<hivex_commit> in order to write the
|
|
||||||
changes to disk. If you call C<hivex_close> without committing then
|
|
||||||
any writes are discarded.
|
|
||||||
|
|
||||||
Hive files internally consist of a "memory dump" of binary blocks
|
|
||||||
(like the C heap), and some of these blocks can be unused. The hivex
|
|
||||||
library never reuses these unused blocks. Instead, to ensure
|
|
||||||
robustness in the face of the partially understood on-disk format,
|
|
||||||
hivex only allocates new blocks after the end of the file, and makes
|
|
||||||
minimal modifications to existing structures in the file to point to
|
|
||||||
these new blocks. This makes hivex slightly less disk-efficient than
|
|
||||||
it could be, but disk is cheap, and registry modifications tend to be
|
|
||||||
very small.
|
|
||||||
|
|
||||||
When deleting nodes, it is possible that this library may leave
|
|
||||||
unreachable live blocks in the hive. This is because certain parts of
|
|
||||||
the hive disk format such as security (sk) records and big data (db)
|
|
||||||
records and classname fields are not well understood (and not
|
|
||||||
documented at all) and we play it safe by not attempting to modify
|
|
||||||
them. Apart from wasting a little bit of disk space, it is not
|
|
||||||
thought that unreachable blocks are a problem.
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item int hivex_commit (hive_h *h, const char *filename, int flags);
|
|
||||||
|
|
||||||
Commit (write) any changes which have been made.
|
|
||||||
|
|
||||||
C<filename> is the new file to write. If C<filename == NULL> then we
|
|
||||||
overwrite the original file (ie. the file name that was passed to
|
|
||||||
C<hivex_open>). C<flags> is not used, always pass 0.
|
|
||||||
|
|
||||||
Returns 0 on success. On error this returns -1 and sets errno.
|
|
||||||
|
|
||||||
Note this does not close the hive handle. You can perform further
|
|
||||||
operations on the hive after committing, including making more
|
|
||||||
modifications. If you no longer wish to use the hive, call
|
|
||||||
C<hivex_close> after this.
|
|
||||||
|
|
||||||
=item hive_node_h hivex_node_add_child (hive_h *h, hive_node_h parent, const char *name);
|
|
||||||
|
|
||||||
Add a new child node named C<name> to the existing node C<parent>.
|
|
||||||
The new child initially has no subnodes and contains no keys or
|
|
||||||
values. The sk-record (security descriptor) is inherited from
|
|
||||||
the parent.
|
|
||||||
|
|
||||||
The parent must not have an existing child called C<name>, so if you
|
|
||||||
want to overwrite an existing child, call C<hivex_node_delete_child>
|
|
||||||
first.
|
|
||||||
|
|
||||||
Returns the node handle. On error this returns 0 and sets errno.
|
|
||||||
|
|
||||||
=item int hivex_node_delete_child (hive_h *h, hive_node_h node);
|
|
||||||
|
|
||||||
Delete the node C<node>. All values at the node and all subnodes are
|
|
||||||
deleted (recursively). The C<node> handle and the handles of all
|
|
||||||
subnodes become invalid. You cannot delete the root node.
|
|
||||||
|
|
||||||
Returns 0 on success. On error this returns -1 and sets errno.
|
|
||||||
|
|
||||||
=item hive_set_value
|
|
||||||
|
|
||||||
The typedef C<hive_set_value> is used in conjunction with the
|
|
||||||
C<hivex_node_set_values> call described below.
|
|
||||||
|
|
||||||
struct hive_set_value {
|
|
||||||
char *key; /* key - a UTF-8 encoded ASCIIZ string */
|
|
||||||
hive_type t; /* type of value field */
|
|
||||||
size_t len; /* length of value field in bytes */
|
|
||||||
char *value; /* value field */
|
|
||||||
};
|
|
||||||
typedef struct hive_set_value hive_set_value;
|
|
||||||
|
|
||||||
To set the default value for a node, you have to pass C<key = "">.
|
|
||||||
|
|
||||||
Note that the C<value> field is just treated as a list of bytes, and
|
|
||||||
is stored directly in the hive. The caller has to ensure correct
|
|
||||||
encoding and endianness, for example converting dwords to little
|
|
||||||
endian.
|
|
||||||
|
|
||||||
The correct type and encoding for values depends on the node and key
|
|
||||||
in the registry, the version of Windows, and sometimes even changes
|
|
||||||
between versions of Windows for the same key. We don't document it
|
|
||||||
here. Often it's not documented at all.
|
|
||||||
|
|
||||||
=item int hivex_node_set_values (hive_h *h, hive_node_h node, size_t nr_values, const hive_set_value *values, int flags);
|
|
||||||
|
|
||||||
This call can be used to set all the (key, value) pairs stored in C<node>.
|
|
||||||
|
|
||||||
C<node> is the node to modify. C<values> is an array of (key, value)
|
|
||||||
pairs. There should be C<nr_values> elements in this array. C<flags>
|
|
||||||
is not used, always pass 0.
|
|
||||||
|
|
||||||
Any existing values stored at the node are discarded, and their
|
|
||||||
C<hive_value_h> handles become invalid. Thus you can remove all
|
|
||||||
values stored at C<node> by passing C<nr_values = 0>.
|
|
||||||
|
|
||||||
Returns 0 on success. On error this returns -1 and sets errno.
|
|
||||||
|
|
||||||
Note that this library does not offer a way to modify just a single
|
|
||||||
key at a node. We don't implement a way to do this efficiently.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head3 WRITE OPERATIONS WHICH ARE NOT SUPPORTED
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Changing the root node.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Creating a new hive file from scratch. This is impossible at present
|
|
||||||
because not all fields in the header are understood.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Modifying or deleting single values at a node.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Modifying security key (sk) records or classnames.
|
|
||||||
Previously we did not understand these records. However now they
|
|
||||||
are well-understood and we could add support if it was required
|
|
||||||
(but nothing much really uses them).
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 THE STRUCTURE OF THE WINDOWS REGISTRY
|
|
||||||
|
|
||||||
Note: To understand the relationship between hives and the common
|
|
||||||
Windows Registry keys (like C<HKEY_LOCAL_MACHINE>) please see the
|
|
||||||
Wikipedia page on the Windows Registry.
|
|
||||||
|
|
||||||
The Windows Registry is split across various binary files, each
|
|
||||||
file being known as a "hive". This library only handles a single
|
|
||||||
hive file at a time.
|
|
||||||
|
|
||||||
Hives are n-ary trees with a single root. Each node in the tree
|
|
||||||
has a name.
|
|
||||||
|
|
||||||
Each node in the tree (including non-leaf nodes) may have an
|
|
||||||
arbitrary list of (key, value) pairs attached to it. It may
|
|
||||||
be the case that one of these pairs has an empty key. This
|
|
||||||
is referred to as the default key for the node.
|
|
||||||
|
|
||||||
The (key, value) pairs are the place where the useful data is
|
|
||||||
stored in the registry. The key is always a string (possibly the
|
|
||||||
empty string for the default key). The value is a typed object
|
|
||||||
(eg. string, int32, binary, etc.).
|
|
||||||
|
|
||||||
=head2 RELATIONSHIP TO .REG FILES
|
|
||||||
|
|
||||||
Although this library does not care about or deal with Windows reg
|
|
||||||
files, it's useful to look at the relationship between the registry
|
|
||||||
itself and reg files because they are so common.
|
|
||||||
|
|
||||||
A reg file is a text representation of the registry, or part of the
|
|
||||||
registry. The actual registry hives that Windows uses are binary
|
|
||||||
files. There are a number of Windows and Linux tools that let you
|
|
||||||
generate reg files, or merge reg files back into the registry hives.
|
|
||||||
Notable amongst them is Microsoft's REGEDIT program (formerly known as
|
|
||||||
REGEDT32).
|
|
||||||
|
|
||||||
A typical reg file will contain many sections looking like this:
|
|
||||||
|
|
||||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Stack]
|
|
||||||
"@"="Generic Stack"
|
|
||||||
"TileInfo"="prop:System.FileCount"
|
|
||||||
"TilePath"=str(2):"%systemroot%\\system32"
|
|
||||||
"ThumbnailCutoff"=dword:00000000
|
|
||||||
"FriendlyTypeName"=hex(2):40,00,25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,\
|
|
||||||
6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,\
|
|
||||||
33,00,32,00,5c,00,73,00,65,00,61,00,72,00,63,00,68,00,66,00,\
|
|
||||||
6f,00,6c,00,64,00,65,00,72,00,2e,00,64,00,6c,00,6c,00,2c,00,\
|
|
||||||
2d,00,39,00,30,00,32,00,38,00,00,00,d8
|
|
||||||
|
|
||||||
Taking this one piece at a time:
|
|
||||||
|
|
||||||
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Stack]
|
|
||||||
|
|
||||||
This is the path to this node in the registry tree. The first part,
|
|
||||||
C<HKEY_LOCAL_MACHINE\SOFTWARE> means that this comes from a hive
|
|
||||||
(file) called C<SOFTWARE>. C<\Classes\Stack> is the real path part,
|
|
||||||
starting at the root node of the C<SOFTWARE> hive.
|
|
||||||
|
|
||||||
Below the node name is a list of zero or more key-value pairs. Any
|
|
||||||
interior or leaf node in the registry may have key-value pairs
|
|
||||||
attached.
|
|
||||||
|
|
||||||
"@"="Generic Stack"
|
|
||||||
|
|
||||||
This is the "default key". In reality (ie. inside the binary hive)
|
|
||||||
the key string is the empty string. In reg files this is written as
|
|
||||||
C<@> but this has no meaning either in the hives themselves or in this
|
|
||||||
library. The value is a string (type 1 - see C<enum hive_type>
|
|
||||||
above).
|
|
||||||
|
|
||||||
"TileInfo"="prop:System.FileCount"
|
|
||||||
|
|
||||||
This is a regular (key, value) pair, with the value being a type 1
|
|
||||||
string. Note that inside the binary file the string is likely to be
|
|
||||||
UTF-16 encoded. This library converts to and from UTF-8 strings
|
|
||||||
transparently.
|
|
||||||
|
|
||||||
"TilePath"=str(2):"%systemroot%\\system32"
|
|
||||||
|
|
||||||
The value in this case has type 2 (expanded string) meaning that some
|
|
||||||
%...% variables get expanded by Windows. (This library doesn't know
|
|
||||||
or care about variable expansion).
|
|
||||||
|
|
||||||
"ThumbnailCutoff"=dword:00000000
|
|
||||||
|
|
||||||
The value in this case is a dword (type 4).
|
|
||||||
|
|
||||||
"FriendlyTypeName"=hex(2):40,00,....
|
|
||||||
|
|
||||||
This value is an expanded string (type 2) represented in the reg file
|
|
||||||
as a series of hex bytes. In this case the string appears to be a
|
|
||||||
UTF-16 string.
|
|
||||||
|
|
||||||
=head1 NOTE ON THE USE OF ERRNO
|
|
||||||
|
|
||||||
Many functions in this library set errno to indicate errors. These
|
|
||||||
are the values of errno you may encounter (this list is not
|
|
||||||
exhaustive):
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item ENOTSUP
|
|
||||||
|
|
||||||
Corrupt or unsupported Registry file format.
|
|
||||||
|
|
||||||
=item ENOKEY
|
|
||||||
|
|
||||||
Missing root key.
|
|
||||||
|
|
||||||
=item EINVAL
|
|
||||||
|
|
||||||
Passed an invalid argument to the function.
|
|
||||||
|
|
||||||
=item EFAULT
|
|
||||||
|
|
||||||
Followed a Registry pointer which goes outside
|
|
||||||
the registry or outside a registry block.
|
|
||||||
|
|
||||||
=item ELOOP
|
|
||||||
|
|
||||||
Registry contains cycles.
|
|
||||||
|
|
||||||
=item ERANGE
|
|
||||||
|
|
||||||
Field in the registry out of range.
|
|
||||||
|
|
||||||
=item EEXIST
|
|
||||||
|
|
||||||
Registry key already exists.
|
|
||||||
|
|
||||||
=item EROFS
|
|
||||||
|
|
||||||
Tried to write to a registry which is not opened for writing.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 ENVIRONMENT VARIABLES
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item HIVEX_DEBUG
|
|
||||||
|
|
||||||
Setting HIVEX_DEBUG=1 will enable very verbose messages. This is
|
|
||||||
useful for debugging problems with the library itself.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<hivexml(1)>,
|
|
||||||
L<hivexget(1)>,
|
|
||||||
L<virt-win-reg(1)>,
|
|
||||||
L<guestfs(3)>,
|
|
||||||
L<http://libguestfs.org/>,
|
|
||||||
L<virt-cat(1)>,
|
|
||||||
L<virt-edit(1)>,
|
|
||||||
L<http://en.wikipedia.org/wiki/Windows_Registry>.
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
|
||||||
|
|
||||||
Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
|
|
||||||
Derived from code by Petter Nordahl-Hagen under a compatible license:
|
|
||||||
Copyright (C) 1997-2007 Petter Nordahl-Hagen.
|
|
||||||
|
|
||||||
Derived from code by Markus Stephany under a compatible license:
|
|
||||||
Copyright (C) 2000-2004 Markus Stephany.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation;
|
|
||||||
version 2.1 of the License.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
See file LICENSE for the full license.
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash -
|
|
||||||
# Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ $# -lt 2 -o $# -gt 3 ]; then
|
|
||||||
echo "hivexget hivefile path [key]"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $# -eq 2 ]; then
|
|
||||||
hivexsh <<EOF
|
|
||||||
load $1
|
|
||||||
cd $2
|
|
||||||
lsval
|
|
||||||
exit
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
key=$3
|
|
||||||
if [ "$key" = "" ]; then
|
|
||||||
key="@"
|
|
||||||
fi
|
|
||||||
hivexsh <<EOF
|
|
||||||
load $1
|
|
||||||
cd $2
|
|
||||||
lsval $key
|
|
||||||
exit
|
|
||||||
EOF
|
|
||||||
fi
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
=encoding utf8
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
hivexget - Get subkey from a Windows Registry binary "hive" file
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
hivexget hivefile '\Path\To\SubKey'
|
|
||||||
|
|
||||||
hivexget hivefile '\Path\To\SubKey' name
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
I<Note:> This is a low-level tool. For a more convenient way to
|
|
||||||
navigate the Windows Registry in Windows virtual machines, see
|
|
||||||
L<virt-win-reg(1)>.
|
|
||||||
|
|
||||||
This program navigates through a Windows Registry binary "hive"
|
|
||||||
file and extracts I<either> all the (key, value) data pairs
|
|
||||||
stored in that subkey I<or> just the single named data item.
|
|
||||||
|
|
||||||
In the first form:
|
|
||||||
|
|
||||||
hivexget hivefile '\Path\To\SubKey'
|
|
||||||
|
|
||||||
C<hivefile> is some Windows Registry binary hive, and C<\Path\To\Subkey>
|
|
||||||
is a path within that hive. I<NB> the path is relative to the top
|
|
||||||
of this hive, and is I<not> the full path as you would use in Windows
|
|
||||||
(eg. C<\HKEY_LOCAL_MACHINE> is not a valid path).
|
|
||||||
|
|
||||||
If the subkey exists, then the output lists all data pairs under this
|
|
||||||
subkey, in a format compatible with C<regedit> in Windows.
|
|
||||||
|
|
||||||
In the second form:
|
|
||||||
|
|
||||||
hivexget hivefile '\Path\To\SubKey' name
|
|
||||||
|
|
||||||
C<hivefile> and path are as above. C<name> is the name of the value
|
|
||||||
of interest (use C<@> for the default value).
|
|
||||||
|
|
||||||
The corresponding data item is printed "raw" (ie. no processing or
|
|
||||||
escaping) except:
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item 1
|
|
||||||
|
|
||||||
If it's a string we will convert it from Windows UTF-16 to UTF-8, if
|
|
||||||
this conversion is possible. The string is printed with a single
|
|
||||||
trailing newline.
|
|
||||||
|
|
||||||
=item 2
|
|
||||||
|
|
||||||
If it's a multiple-string value, each string is printed on a separate
|
|
||||||
line.
|
|
||||||
|
|
||||||
=item 3
|
|
||||||
|
|
||||||
If it's a numeric value, it is printed as a decimal number.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<hivex(3)>,
|
|
||||||
L<hivexml(1)>,
|
|
||||||
L<hivexsh(1)>,
|
|
||||||
L<virt-win-reg(1)>,
|
|
||||||
L<guestfs(3)>,
|
|
||||||
L<http://libguestfs.org/>,
|
|
||||||
L<virt-cat(1)>,
|
|
||||||
L<virt-edit(1)>.
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
|
||||||
|
|
||||||
Copyright (C) 2009 Red Hat Inc.
|
|
||||||
|
|
||||||
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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
345
hivex/hivexml.c
345
hivex/hivexml.c
@@ -1,345 +0,0 @@
|
|||||||
/* hivexml - Convert Windows Registry "hive" to XML file.
|
|
||||||
* Copyright (C) 2009 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <libxml/xmlwriter.h>
|
|
||||||
|
|
||||||
#include "hivex.h"
|
|
||||||
|
|
||||||
#ifdef HAVE_GETTEXT
|
|
||||||
#include "gettext.h"
|
|
||||||
#define _(str) dgettext(PACKAGE, (str))
|
|
||||||
//#define N_(str) dgettext(PACKAGE, (str))
|
|
||||||
#else
|
|
||||||
#define _(str) str
|
|
||||||
//#define N_(str) str
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Callback functions. */
|
|
||||||
static int node_start (hive_h *, void *, hive_node_h, const char *name);
|
|
||||||
static int node_end (hive_h *, void *, hive_node_h, const char *name);
|
|
||||||
static int value_string (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
|
|
||||||
static int value_multiple_strings (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, char **argv);
|
|
||||||
static int value_string_invalid_utf16 (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *str);
|
|
||||||
static int value_dword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int32_t);
|
|
||||||
static int value_qword (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, int64_t);
|
|
||||||
static int value_binary (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
static int value_none (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
static int value_other (hive_h *, void *, hive_node_h, hive_value_h, hive_type t, size_t len, const char *key, const char *value);
|
|
||||||
|
|
||||||
static struct hivex_visitor visitor = {
|
|
||||||
.node_start = node_start,
|
|
||||||
.node_end = node_end,
|
|
||||||
.value_string = value_string,
|
|
||||||
.value_multiple_strings = value_multiple_strings,
|
|
||||||
.value_string_invalid_utf16 = value_string_invalid_utf16,
|
|
||||||
.value_dword = value_dword,
|
|
||||||
.value_qword = value_qword,
|
|
||||||
.value_binary = value_binary,
|
|
||||||
.value_none = value_none,
|
|
||||||
.value_other = value_other
|
|
||||||
};
|
|
||||||
|
|
||||||
#define XML_CHECK(proc, args) \
|
|
||||||
do { \
|
|
||||||
if ((proc args) == -1) { \
|
|
||||||
fprintf (stderr, _("%s: failed to write XML document\n"), #proc); \
|
|
||||||
exit (EXIT_FAILURE); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char *argv[])
|
|
||||||
{
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
bindtextdomain (PACKAGE, LOCALEBASEDIR);
|
|
||||||
textdomain (PACKAGE);
|
|
||||||
|
|
||||||
int c;
|
|
||||||
int open_flags = 0;
|
|
||||||
int visit_flags = 0;
|
|
||||||
|
|
||||||
while ((c = getopt (argc, argv, "dk")) != EOF) {
|
|
||||||
switch (c) {
|
|
||||||
case 'd':
|
|
||||||
open_flags |= HIVEX_OPEN_DEBUG;
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
visit_flags |= HIVEX_VISIT_SKIP_BAD;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf (stderr, "hivexml [-dk] regfile > output.xml\n");
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind + 1 != argc) {
|
|
||||||
fprintf (stderr, _("hivexml: missing name of input file\n"));
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
hive_h *h = hivex_open (argv[optind], open_flags);
|
|
||||||
if (h == NULL) {
|
|
||||||
perror (argv[optind]);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note both this macro, and xmlTextWriterStartDocument leak memory. There
|
|
||||||
* doesn't seem to be any way to recover that memory, but it's not a
|
|
||||||
* large amount.
|
|
||||||
*/
|
|
||||||
LIBXML_TEST_VERSION;
|
|
||||||
|
|
||||||
xmlTextWriterPtr writer;
|
|
||||||
writer = xmlNewTextWriterFilename ("/dev/stdout", 0);
|
|
||||||
if (writer == NULL) {
|
|
||||||
fprintf (stderr, _("xmlNewTextWriterFilename: failed to create XML writer\n"));
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
XML_CHECK (xmlTextWriterStartDocument, (writer, NULL, "utf-8", NULL));
|
|
||||||
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "hive"));
|
|
||||||
|
|
||||||
if (hivex_visit (h, &visitor, sizeof visitor, writer, visit_flags) == -1) {
|
|
||||||
perror (argv[optind]);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hivex_close (h) == -1) {
|
|
||||||
perror (argv[optind]);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
XML_CHECK (xmlTextWriterEndElement, (writer));
|
|
||||||
XML_CHECK (xmlTextWriterEndDocument, (writer));
|
|
||||||
xmlFreeTextWriter (writer);
|
|
||||||
|
|
||||||
exit (EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
node_start (hive_h *h, void *writer_v, hive_node_h node, const char *name)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "node"));
|
|
||||||
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "name", BAD_CAST name));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
node_end (hive_h *h, void *writer_v, hive_node_h node, const char *name)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
XML_CHECK (xmlTextWriterEndElement, (writer));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
start_value (xmlTextWriterPtr writer,
|
|
||||||
const char *key, const char *type, const char *encoding)
|
|
||||||
{
|
|
||||||
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "value"));
|
|
||||||
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "type", BAD_CAST type));
|
|
||||||
if (encoding)
|
|
||||||
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "encoding", BAD_CAST encoding));
|
|
||||||
if (*key)
|
|
||||||
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "key", BAD_CAST key));
|
|
||||||
else /* default key */
|
|
||||||
XML_CHECK (xmlTextWriterWriteAttribute, (writer, BAD_CAST "default", BAD_CAST "1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
end_value (xmlTextWriterPtr writer)
|
|
||||||
{
|
|
||||||
XML_CHECK (xmlTextWriterEndElement, (writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_string (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, const char *str)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
const char *type;
|
|
||||||
|
|
||||||
switch (t) {
|
|
||||||
case hive_t_string: type = "string"; break;
|
|
||||||
case hive_t_expand_string: type = "expand"; break;
|
|
||||||
case hive_t_link: type = "link"; break;
|
|
||||||
|
|
||||||
case hive_t_none:
|
|
||||||
case hive_t_binary:
|
|
||||||
case hive_t_dword:
|
|
||||||
case hive_t_dword_be:
|
|
||||||
case hive_t_multiple_strings:
|
|
||||||
case hive_t_resource_list:
|
|
||||||
case hive_t_full_resource_description:
|
|
||||||
case hive_t_resource_requirements_list:
|
|
||||||
case hive_t_qword:
|
|
||||||
abort (); /* internal error - should not happen */
|
|
||||||
|
|
||||||
default:
|
|
||||||
type = "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
start_value (writer, key, type, NULL);
|
|
||||||
XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST str));
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_multiple_strings (hive_h *h, void *writer_v, hive_node_h node,
|
|
||||||
hive_value_h value, hive_type t, size_t len,
|
|
||||||
const char *key, char **argv)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
start_value (writer, key, "string-list", NULL);
|
|
||||||
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; argv[i] != NULL; ++i) {
|
|
||||||
XML_CHECK (xmlTextWriterStartElement, (writer, BAD_CAST "string"));
|
|
||||||
XML_CHECK (xmlTextWriterWriteString, (writer, BAD_CAST argv[i]));
|
|
||||||
XML_CHECK (xmlTextWriterEndElement, (writer));
|
|
||||||
}
|
|
||||||
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_string_invalid_utf16 (hive_h *h, void *writer_v, hive_node_h node,
|
|
||||||
hive_value_h value, hive_type t, size_t len,
|
|
||||||
const char *key,
|
|
||||||
const char *str /* original data */)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
const char *type;
|
|
||||||
|
|
||||||
switch (t) {
|
|
||||||
case hive_t_string: type = "bad-string"; break;
|
|
||||||
case hive_t_expand_string: type = "bad-expand"; break;
|
|
||||||
case hive_t_link: type = "bad-link"; break;
|
|
||||||
case hive_t_multiple_strings: type = "bad-string-list"; break;
|
|
||||||
|
|
||||||
case hive_t_none:
|
|
||||||
case hive_t_binary:
|
|
||||||
case hive_t_dword:
|
|
||||||
case hive_t_dword_be:
|
|
||||||
case hive_t_resource_list:
|
|
||||||
case hive_t_full_resource_description:
|
|
||||||
case hive_t_resource_requirements_list:
|
|
||||||
case hive_t_qword:
|
|
||||||
abort (); /* internal error - should not happen */
|
|
||||||
|
|
||||||
default:
|
|
||||||
type = "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
start_value (writer, key, type, "base64");
|
|
||||||
XML_CHECK (xmlTextWriterWriteBase64, (writer, str, 0, len));
|
|
||||||
end_value (writer);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_dword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, int32_t v)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
start_value (writer, key, "int32", NULL);
|
|
||||||
XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi32, v));
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_qword (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, int64_t v)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
start_value (writer, key, "int64", NULL);
|
|
||||||
XML_CHECK (xmlTextWriterWriteFormatString, (writer, "%" PRIi64, v));
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_binary (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, const char *v)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
start_value (writer, key, "binary", "base64");
|
|
||||||
XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_none (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, const char *v)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
start_value (writer, key, "none", "base64");
|
|
||||||
if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
|
|
||||||
end_value (writer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
value_other (hive_h *h, void *writer_v, hive_node_h node, hive_value_h value,
|
|
||||||
hive_type t, size_t len, const char *key, const char *v)
|
|
||||||
{
|
|
||||||
xmlTextWriterPtr writer = (xmlTextWriterPtr) writer_v;
|
|
||||||
const char *type;
|
|
||||||
|
|
||||||
switch (t) {
|
|
||||||
case hive_t_none:
|
|
||||||
case hive_t_binary:
|
|
||||||
case hive_t_dword:
|
|
||||||
case hive_t_dword_be:
|
|
||||||
case hive_t_qword:
|
|
||||||
case hive_t_string:
|
|
||||||
case hive_t_expand_string:
|
|
||||||
case hive_t_link:
|
|
||||||
case hive_t_multiple_strings:
|
|
||||||
abort (); /* internal error - should not happen */
|
|
||||||
|
|
||||||
case hive_t_resource_list: type = "resource-list"; break;
|
|
||||||
case hive_t_full_resource_description: type = "resource-description"; break;
|
|
||||||
case hive_t_resource_requirements_list: type = "resource-requirements"; break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
type = "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
start_value (writer, key, type, "base64");
|
|
||||||
if (len > 0) XML_CHECK (xmlTextWriterWriteBase64, (writer, v, 0, len));
|
|
||||||
end_value (writer);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
=encoding utf8
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
hivexml - Convert Windows Registry binary "hive" into XML
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
hivexml [-dk] hivefile > output.xml
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
This program converts a single Windows Registry binary "hive"
|
|
||||||
file into a self-describing XML format.
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item B<-d>
|
|
||||||
|
|
||||||
Enable lots of debug messages. If you find a Registry file
|
|
||||||
that this program cannot parse, please enable this option and
|
|
||||||
post the complete output I<and> the Registry file in your
|
|
||||||
bug report.
|
|
||||||
|
|
||||||
=item B<-k>
|
|
||||||
|
|
||||||
Keep going even if we find errors in the Registry file. This
|
|
||||||
skips over any parts of the Registry that we cannot read.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<hivex(3)>,
|
|
||||||
L<hivexget(1)>,
|
|
||||||
L<hivexsh(1)>,
|
|
||||||
L<virt-win-reg(1)>,
|
|
||||||
L<guestfs(3)>,
|
|
||||||
L<http://libguestfs.org/>,
|
|
||||||
L<virt-cat(1)>,
|
|
||||||
L<virt-edit(1)>.
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
|
||||||
|
|
||||||
Copyright (C) 2009 Red Hat Inc.
|
|
||||||
|
|
||||||
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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
1094
hivex/hivexsh.c
1094
hivex/hivexsh.c
File diff suppressed because it is too large
Load Diff
@@ -1,287 +0,0 @@
|
|||||||
=encoding utf8
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
hivexsh - Windows Registry hive shell
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
hivexsh [-options] [hivefile]
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
This program provides a simple shell for navigating Windows Registry
|
|
||||||
'hive' files. It uses the hivex library for access to these binary
|
|
||||||
files.
|
|
||||||
|
|
||||||
Firstly you will need to provide a hive file from a Windows operating
|
|
||||||
system. The hive files are usually located in
|
|
||||||
C<C:\Windows\System32\Config> and have names like C<software>,
|
|
||||||
C<system> etc (without any file extension). For more information
|
|
||||||
about hive files, read L<hivex(3)>. For information about downloading
|
|
||||||
files from virtual machines, read L<virt-cat(1)> and L<guestfish(1)>.
|
|
||||||
|
|
||||||
You can provide the name of the hive file to examine on the command
|
|
||||||
line. For example:
|
|
||||||
|
|
||||||
hivexsh software
|
|
||||||
|
|
||||||
Or you can start C<hivexsh> without any arguments, and immediately use
|
|
||||||
the C<load> command to load a hive:
|
|
||||||
|
|
||||||
$ hivexsh
|
|
||||||
|
|
||||||
Welcome to hivexsh, the hivex interactive shell for examining
|
|
||||||
Windows Registry binary hive files.
|
|
||||||
|
|
||||||
Type: 'help' for help with commands
|
|
||||||
'quit' to quit the shell
|
|
||||||
|
|
||||||
> load software
|
|
||||||
software\>
|
|
||||||
|
|
||||||
Navigate through the hive's keys using the C<cd> command, as if it
|
|
||||||
contained a filesystem, and use C<ls> to list the subkeys of the
|
|
||||||
current key. Other commands are listed below.
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item B<-d>
|
|
||||||
|
|
||||||
Enable lots of debug messages. If you find a Registry file that this
|
|
||||||
program cannot parse, please enable this option and post the complete
|
|
||||||
output I<and> the Registry hive file in your bug report.
|
|
||||||
|
|
||||||
=item B<-f> filename
|
|
||||||
|
|
||||||
Read commands from C<filename> instead of stdin. To write a hivexsh
|
|
||||||
script, use:
|
|
||||||
|
|
||||||
#!/usr/bin/hivexsh -f
|
|
||||||
|
|
||||||
=item B<-w>
|
|
||||||
|
|
||||||
If this option is given, then writes are allowed to the hive
|
|
||||||
(see L</commit> command below, and the discussion of
|
|
||||||
modifying hives in L<hivex(3)/WRITING TO HIVE FILES>).
|
|
||||||
|
|
||||||
B<Important Note:> Even if you specify this option, nothing is written
|
|
||||||
to a hive unless you call the L</commit> command. If you exit the
|
|
||||||
shell without committing, all changes will be discarded.
|
|
||||||
|
|
||||||
If this option is not given, then write commands are disabled.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 COMMANDS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item B<add> name
|
|
||||||
|
|
||||||
Add a subkey named C<name> below the current node. The name may
|
|
||||||
contain spaces and punctuation characters, and does not need to be
|
|
||||||
quoted.
|
|
||||||
|
|
||||||
The new key will have no subkeys and no values (see C<setval>).
|
|
||||||
|
|
||||||
There must be no existing subkey called C<name>, or this command will
|
|
||||||
fail. To replace an existing subkey, delete it first like this:
|
|
||||||
|
|
||||||
cd name
|
|
||||||
del
|
|
||||||
|
|
||||||
=item B<cd> path
|
|
||||||
|
|
||||||
Change to the subkey C<path>. Use Windows-style backslashes to
|
|
||||||
separate path elements, and start with a backslash in order to start
|
|
||||||
from the root of the hive. For example:
|
|
||||||
|
|
||||||
cd \Classes\*
|
|
||||||
|
|
||||||
moves from the root node, to the C<Classes> node, to the C<*> node.
|
|
||||||
If you were already at the root node, you could do this instead:
|
|
||||||
|
|
||||||
cd Classes\*
|
|
||||||
|
|
||||||
or even:
|
|
||||||
|
|
||||||
cd Classes
|
|
||||||
cd *
|
|
||||||
|
|
||||||
Path elements (node names) are matched case insensitively, and
|
|
||||||
characters like space, C<*>, and C<?> have I<no> special significance.
|
|
||||||
|
|
||||||
C<cd ..> may be used to go to the parent directory.
|
|
||||||
|
|
||||||
C<cd> without any arguments prints the current path.
|
|
||||||
|
|
||||||
Be careful with C<cd \> since the readline library has an undocumented
|
|
||||||
behaviour where it will think the final backslash is a continuation
|
|
||||||
(it reads the next line of input and appends it). Put a single space
|
|
||||||
after the backslash.
|
|
||||||
|
|
||||||
=item B<close> | B<unload>
|
|
||||||
|
|
||||||
Close the currently loaded hive.
|
|
||||||
|
|
||||||
If you modified the hive, all uncommitted writes are lost when you
|
|
||||||
call this command (or if the shell exits). You have to call C<commit>
|
|
||||||
to write changes.
|
|
||||||
|
|
||||||
=item B<commit> [newfile]
|
|
||||||
|
|
||||||
Commit changes to the hive. If the optional C<newfile> parameter is
|
|
||||||
supplied, then the hive is written to that file, else the original
|
|
||||||
file is overwritten.
|
|
||||||
|
|
||||||
Note that you have to specify the C<-w> flag, otherwise no writes are
|
|
||||||
allowed.
|
|
||||||
|
|
||||||
=item B<del>
|
|
||||||
|
|
||||||
Delete the current node and everything beneath it. The current
|
|
||||||
directory is moved up one level (as if you did C<cd ..>) after
|
|
||||||
this command.
|
|
||||||
|
|
||||||
You cannot delete the root node.
|
|
||||||
|
|
||||||
=item B<exit> | B<quit>
|
|
||||||
|
|
||||||
Exit the shell.
|
|
||||||
|
|
||||||
=item B<load> hivefile
|
|
||||||
|
|
||||||
Load the binary hive named C<hivefile>. The currently loaded hive, if
|
|
||||||
any, is closed. The current directory is changed back to the root
|
|
||||||
node.
|
|
||||||
|
|
||||||
=item B<ls>
|
|
||||||
|
|
||||||
List the subkeys of the current hive Registry key. Note this command
|
|
||||||
does not take any arguments.
|
|
||||||
|
|
||||||
=item B<lsval> [key]
|
|
||||||
|
|
||||||
List the (key, value) pairs of the current hive Registry key. If no
|
|
||||||
argument is given then all pairs are displayed. If C<key> is given,
|
|
||||||
then the value of the named key is displayed. If C<@> is given, then
|
|
||||||
the value of the default key is displayed.
|
|
||||||
|
|
||||||
=item B<setval> nrvals
|
|
||||||
|
|
||||||
This command replaces all (key, value) pairs at the current node with
|
|
||||||
the values in subsequent input. C<nrvals> is the number of values
|
|
||||||
(ie. (key, value) pairs), and any existing values at this node are
|
|
||||||
deleted. So C<setval 0> just deletes any values at the current node.
|
|
||||||
|
|
||||||
The command reads 2 * nrvals lines of input, with each pair of
|
|
||||||
lines of input corresponding to a key and a value to add.
|
|
||||||
|
|
||||||
For example, the following setval command replaces whatever is at the
|
|
||||||
current node with two (key, value) pairs. The default key is set to
|
|
||||||
the UTF16-LE-encoded string "abcd". The other value is named
|
|
||||||
"ANumber" and is a little-endian DWORD 0x12345678.
|
|
||||||
|
|
||||||
setval 2
|
|
||||||
@
|
|
||||||
string:abcd
|
|
||||||
ANumber
|
|
||||||
dword:12345678
|
|
||||||
|
|
||||||
The first line of each pair is the key (the special key C<@> means
|
|
||||||
the default key, but you can also use a blank line).
|
|
||||||
|
|
||||||
The second line of each pair is the value, which has a special format
|
|
||||||
C<type:value> with possible types summarized in the table below:
|
|
||||||
|
|
||||||
none No data is stored, and the type is set to 0.
|
|
||||||
|
|
||||||
string:abc "abc" is stored as a UTF16-LE-encoded
|
|
||||||
string (type 1). Note that only 7 bit
|
|
||||||
ASCII strings are supported as input.
|
|
||||||
|
|
||||||
expandstring:... Same as string but with type 2.
|
|
||||||
|
|
||||||
dword:0x01234567 A DWORD (type 4) with the hex value
|
|
||||||
0x01234567. You can also use decimal
|
|
||||||
or octal numbers here.
|
|
||||||
|
|
||||||
qword:0x0123456789abcdef
|
|
||||||
A QWORD (type 11) with the hex value
|
|
||||||
0x0123456789abcdef. You can also use
|
|
||||||
decimal or octal numbers here.
|
|
||||||
|
|
||||||
hex:<type>:<hexbytes>
|
|
||||||
hex:1:41,00,42,00,43,00,44,00,00,00
|
|
||||||
This is the generic way to enter any
|
|
||||||
value. <type> is the integer value type.
|
|
||||||
<hexbytes> is a list of pairs of hex
|
|
||||||
digits which are treated as bytes.
|
|
||||||
(Any non-hex-digits here are ignored,
|
|
||||||
so you can separate bytes with commas
|
|
||||||
or spaces if you want).
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 EXAMPLE
|
|
||||||
|
|
||||||
$ guestfish --ro -i Windows7
|
|
||||||
><fs> download win:c:\windows\system32\config\software software
|
|
||||||
><fs> quit
|
|
||||||
|
|
||||||
$ hivexsh software
|
|
||||||
|
|
||||||
Welcome to hivexsh, the hivex interactive shell for examining
|
|
||||||
Windows Registry binary hive files.
|
|
||||||
|
|
||||||
Type: 'help' for help with commands
|
|
||||||
'quit' to quit the shell
|
|
||||||
|
|
||||||
software\> ls
|
|
||||||
ATI Technologies
|
|
||||||
Classes
|
|
||||||
Clients
|
|
||||||
Intel
|
|
||||||
Microsoft
|
|
||||||
ODBC
|
|
||||||
Policies
|
|
||||||
RegisteredApplications
|
|
||||||
Sonic
|
|
||||||
Wow6432Node
|
|
||||||
software\> quit
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<hivex(3)>,
|
|
||||||
L<hivexget(1)>,
|
|
||||||
L<hivexml(1)>,
|
|
||||||
L<virt-win-reg(1)>,
|
|
||||||
L<guestfs(3)>,
|
|
||||||
L<http://libguestfs.org/>,
|
|
||||||
L<virt-cat(1)>,
|
|
||||||
L<virt-edit(1)>.
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Richard W.M. Jones (C<rjones at redhat dot com>)
|
|
||||||
|
|
||||||
=head1 COPYRIGHT
|
|
||||||
|
|
||||||
Copyright (C) 2009-2010 Red Hat Inc.
|
|
||||||
|
|
||||||
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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# libguestfs
|
|
||||||
# Copyright (C) 2009 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
EXTRA_DIST = minimal
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
This directory contains tests for the hivex library.
|
|
||||||
|
|
||||||
'minimal' is a valid registry containing a single root nk (with
|
|
||||||
associated sk) which was created by chopping out everything possible
|
|
||||||
from a Windows 2003 software hive and then doing lots of hand edits on
|
|
||||||
the result. There is no "source" for it as such, it is just a
|
|
||||||
hand-crafted binary blob.
|
|
||||||
|
|
||||||
- Richard W.M. Jones 2010-01-23.
|
|
||||||
BIN
hivex/t/minimal
BIN
hivex/t/minimal
Binary file not shown.
@@ -1,56 +0,0 @@
|
|||||||
# libguestfs
|
|
||||||
# Copyright (C) 2009 Red Hat Inc.
|
|
||||||
#
|
|
||||||
# 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 2 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, write to the Free Software
|
|
||||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
|
|
||||||
# OCaml Windows Registry visualizer. This was used while reverse
|
|
||||||
# engineering the hive format, and is not normally compiled. If you
|
|
||||||
# do with to compile it, you'll need ocaml-bitstring-devel and
|
|
||||||
# ocaml-extlib-devel. Also you'll need a collection of hive files
|
|
||||||
# from Windows machines to experiment with.
|
|
||||||
#
|
|
||||||
# We use '-w y' (disable unused variable warnings) because these
|
|
||||||
# warnings aren't very reliable with heavily preprocessed code like
|
|
||||||
# that produced by bitstring.
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
visualizer.ml \
|
|
||||||
visualizer_utils.ml \
|
|
||||||
visualizer_NT_time.ml \
|
|
||||||
clearheaderfields.ml \
|
|
||||||
fillemptyhbins.ml \
|
|
||||||
truncatefile.ml \
|
|
||||||
counter.mli \
|
|
||||||
counter.ml
|
|
||||||
|
|
||||||
visualizer.opt: counter.mli counter.ml visualizer_utils.ml visualizer_NT_time.ml visualizer.ml
|
|
||||||
ocamlfind ocamlopt -w y \
|
|
||||||
-package bitstring,bitstring.syntax,extlib \
|
|
||||||
-syntax camlp4 -linkpkg $^ -o $@
|
|
||||||
|
|
||||||
fillemptyhbins.opt: fillemptyhbins.ml
|
|
||||||
ocamlfind ocamlopt -w y \
|
|
||||||
-package bitstring,bitstring.syntax,extlib \
|
|
||||||
-syntax camlp4 -linkpkg $^ -o $@
|
|
||||||
|
|
||||||
clearheaderfields.opt: visualizer_utils.ml clearheaderfields.ml
|
|
||||||
ocamlfind ocamlopt -w y \
|
|
||||||
-package bitstring,bitstring.syntax,extlib \
|
|
||||||
-syntax camlp4 -linkpkg $^ -o $@
|
|
||||||
|
|
||||||
truncatefile.opt: visualizer_utils.ml truncatefile.ml
|
|
||||||
ocamlfind ocamlopt -w y \
|
|
||||||
-package bitstring,bitstring.syntax,extlib \
|
|
||||||
-syntax camlp4 -linkpkg $^ -o $@
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open Bitstring
|
|
||||||
open ExtString
|
|
||||||
open Printf
|
|
||||||
open Visualizer_utils
|
|
||||||
|
|
||||||
let () =
|
|
||||||
if Array.length Sys.argv <> 2 then (
|
|
||||||
eprintf "Error: missing argument.
|
|
||||||
Usage: %s hivefile
|
|
||||||
" Sys.executable_name;
|
|
||||||
exit 1
|
|
||||||
)
|
|
||||||
|
|
||||||
let filename = Sys.argv.(1)
|
|
||||||
|
|
||||||
(* Load the file. *)
|
|
||||||
let bits = bitstring_of_file filename
|
|
||||||
|
|
||||||
(* Split into header + data at the 4KB boundary. *)
|
|
||||||
let header, data = takebits (4096 * 8) bits, dropbits (4096 * 8) bits
|
|
||||||
|
|
||||||
(* Read the header fields. *)
|
|
||||||
let seq, last_modified, major, minor, unknown1, unknown2,
|
|
||||||
root_key, end_pages, unknown3, fname =
|
|
||||||
bitmatch header with
|
|
||||||
| { "regf" : 4*8 : string;
|
|
||||||
seq1 : 4*8 : littleendian;
|
|
||||||
seq2 : 4*8 : littleendian;
|
|
||||||
last_modified : 64 : bitstring;
|
|
||||||
major : 4*8 : littleendian;
|
|
||||||
minor : 4*8 : littleendian;
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
unknown2 : 4*8 : littleendian;
|
|
||||||
root_key : 4*8 : littleendian;
|
|
||||||
end_pages : 4*8 : littleendian;
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
fname : 64*8 : string;
|
|
||||||
unknownguid1 : 16*8 : bitstring;
|
|
||||||
unknownguid2 : 16*8 : bitstring;
|
|
||||||
unknown4 : 4*8 : littleendian;
|
|
||||||
unknownguid3 : 16*8 : bitstring;
|
|
||||||
unknown5 : 4*8 : string;
|
|
||||||
unknown6 : 340*8 : bitstring;
|
|
||||||
csum : 4*8
|
|
||||||
: littleendian, save_offset_to (crc_offset),
|
|
||||||
check (assert (crc_offset = 0x1fc * 8); true);
|
|
||||||
unknown7 : (0x1000-0x200)*8 : bitstring } ->
|
|
||||||
seq1, last_modified, major, minor, unknown1, unknown2,
|
|
||||||
root_key, end_pages, unknown3, fname
|
|
||||||
| {_} -> assert false
|
|
||||||
|
|
||||||
(* Create a new header, but with unknown fields cleared. Do it in
|
|
||||||
* two parts, first creating everything up to the checksum, then
|
|
||||||
* calculating the checksum and appending checksum and the final
|
|
||||||
* field.
|
|
||||||
*)
|
|
||||||
let header =
|
|
||||||
let zeroguid = zeroes_bitstring (16*8) in
|
|
||||||
let before_csum =
|
|
||||||
BITSTRING {
|
|
||||||
"regf" : 4*8 : string;
|
|
||||||
seq : 4*8 : littleendian;
|
|
||||||
seq : 4*8 : littleendian;
|
|
||||||
last_modified : 64 : bitstring;
|
|
||||||
major : 4*8 : littleendian;
|
|
||||||
minor : 4*8 : littleendian;
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
unknown2 : 4*8 : littleendian;
|
|
||||||
root_key : 4*8 : littleendian;
|
|
||||||
end_pages : 4*8 : littleendian;
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
fname : 64*8 : string;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
0_l : 4*8 : littleendian;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
0_l : 4*8 : littleendian;
|
|
||||||
zeroes_bitstring (340*8) : 340*8 : bitstring
|
|
||||||
} in
|
|
||||||
assert (bitstring_length before_csum = 0x1fc * 8);
|
|
||||||
let csum = bitstring_fold_left_int32_le Int32.logxor 0_l before_csum in
|
|
||||||
let csum_and_after =
|
|
||||||
BITSTRING {
|
|
||||||
csum : 4*8 : littleendian;
|
|
||||||
zeroes_bitstring ((0x1000-0x200)*8) : (0x1000-0x200)*8 : bitstring
|
|
||||||
} in
|
|
||||||
let new_header = concat [before_csum; csum_and_after] in
|
|
||||||
assert (bitstring_length header = bitstring_length new_header);
|
|
||||||
new_header
|
|
||||||
|
|
||||||
(* Write it. *)
|
|
||||||
let () =
|
|
||||||
let file = concat [header; data] in
|
|
||||||
bitstring_to_file file filename
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
(* Basic counting module.
|
|
||||||
|
|
||||||
Copyright (C) 2006 Merjis Ltd.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*)
|
|
||||||
|
|
||||||
type 'a t = ('a, int ref) Hashtbl.t
|
|
||||||
|
|
||||||
let create () =
|
|
||||||
Hashtbl.create 13
|
|
||||||
|
|
||||||
let get_ref counter thing =
|
|
||||||
try
|
|
||||||
Hashtbl.find counter thing
|
|
||||||
with
|
|
||||||
Not_found ->
|
|
||||||
let r = ref 0 in
|
|
||||||
Hashtbl.add counter thing r;
|
|
||||||
r
|
|
||||||
|
|
||||||
let incr counter thing =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
incr r
|
|
||||||
|
|
||||||
let decr counter thing =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
decr r
|
|
||||||
|
|
||||||
let add counter thing n =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
r := !r + n
|
|
||||||
|
|
||||||
let sub counter thing n =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
r := !r - n
|
|
||||||
|
|
||||||
let set counter thing n =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
r := n
|
|
||||||
|
|
||||||
(* Don't use get_ref, to avoid unnecessarily creating 'ref 0's. *)
|
|
||||||
let get counter thing =
|
|
||||||
try
|
|
||||||
!(Hashtbl.find counter thing)
|
|
||||||
with
|
|
||||||
Not_found -> 0
|
|
||||||
|
|
||||||
(* This is a common pair of operations, worth optimising. *)
|
|
||||||
let incr_get counter thing =
|
|
||||||
let r = get_ref counter thing in
|
|
||||||
Pervasives.incr r;
|
|
||||||
!r
|
|
||||||
|
|
||||||
let zero = Hashtbl.remove
|
|
||||||
|
|
||||||
let read counter =
|
|
||||||
let counts =
|
|
||||||
Hashtbl.fold (
|
|
||||||
fun thing r xs ->
|
|
||||||
let r = !r in
|
|
||||||
if r <> 0 then (r, thing) :: xs
|
|
||||||
else xs
|
|
||||||
) counter [] in
|
|
||||||
List.sort (fun (a, _) (b, _) -> compare (b : int) (a : int)) counts
|
|
||||||
|
|
||||||
let length = Hashtbl.length
|
|
||||||
|
|
||||||
let total counter =
|
|
||||||
let total = ref 0 in
|
|
||||||
Hashtbl.iter (fun _ r -> total := !total + !r) counter;
|
|
||||||
!total
|
|
||||||
|
|
||||||
let clear = Hashtbl.clear
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
(** Basic counting module.
|
|
||||||
|
|
||||||
Copyright (C) 2006 Merjis Ltd.
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*)
|
|
||||||
|
|
||||||
type 'a t
|
|
||||||
(** Count items of type ['a]. *)
|
|
||||||
|
|
||||||
val create : unit -> 'a t
|
|
||||||
(** Create a new counter. *)
|
|
||||||
|
|
||||||
val incr : 'a t -> 'a -> unit
|
|
||||||
(** [incr counter thing] adds one to the count of [thing]s in [counter]. *)
|
|
||||||
|
|
||||||
val decr : 'a t -> 'a -> unit
|
|
||||||
(** [decr counter thing] subtracts one to the count of [thing]s in [counter]. *)
|
|
||||||
|
|
||||||
val add : 'a t -> 'a -> int -> unit
|
|
||||||
(** [add counter thing n] adds [n] to the count of [thing]s in [counter]. *)
|
|
||||||
|
|
||||||
val sub : 'a t -> 'a -> int -> unit
|
|
||||||
(** [sub counter thing n] subtracts [n] to the count of [thing]s in [counter]. *)
|
|
||||||
|
|
||||||
val set : 'a t -> 'a -> int -> unit
|
|
||||||
(** [set counter thing n] sets the count of [thing]s to [n]. *)
|
|
||||||
|
|
||||||
val get : 'a t -> 'a -> int
|
|
||||||
(** [get counter thing] returns the count of [thing]s. (Returns 0 for
|
|
||||||
* [thing]s which have not been added.
|
|
||||||
*)
|
|
||||||
|
|
||||||
val incr_get : 'a t -> 'a -> int
|
|
||||||
(** Faster form of {!Counter.incr} followed by {!Counter.get}. *)
|
|
||||||
|
|
||||||
val zero : 'a t -> 'a -> unit
|
|
||||||
(** [zero counter thing] sets the count of [thing]s to 0.
|
|
||||||
* See also {!Counter.clear}.
|
|
||||||
*)
|
|
||||||
|
|
||||||
val read : 'a t -> (int * 'a) list
|
|
||||||
(** [read counter] reads the frequency of each thing. They are sorted
|
|
||||||
* with the thing appearing most frequently first. Only things occurring
|
|
||||||
* non-zero times are returned.
|
|
||||||
*)
|
|
||||||
|
|
||||||
val length : 'a t -> int
|
|
||||||
(** Return the number of distinct things. See also {!Counter.total} *)
|
|
||||||
|
|
||||||
val total : 'a t -> int
|
|
||||||
(** Return the number of things counted (the total number of counts).
|
|
||||||
* See also {!Counter.length}
|
|
||||||
*)
|
|
||||||
|
|
||||||
val clear : 'a t -> unit
|
|
||||||
(** [clear counter] zeroes all counts. *)
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open Bitstring
|
|
||||||
open ExtString
|
|
||||||
open Printf
|
|
||||||
|
|
||||||
let () =
|
|
||||||
if Array.length Sys.argv <> 3 then (
|
|
||||||
eprintf "Error: missing argument.
|
|
||||||
Usage: %s hivefile startoffset
|
|
||||||
" Sys.executable_name;
|
|
||||||
exit 1
|
|
||||||
)
|
|
||||||
|
|
||||||
let filename = Sys.argv.(1)
|
|
||||||
let offset = int_of_string Sys.argv.(2)
|
|
||||||
|
|
||||||
(* Load the file. *)
|
|
||||||
let bits = bitstring_of_file filename
|
|
||||||
|
|
||||||
(* Split into header + data at the 4KB boundary. *)
|
|
||||||
let header, data = takebits (4096 * 8) bits, dropbits (4096 * 8) bits
|
|
||||||
|
|
||||||
(* Overwrite everything after @offset, so ... *)
|
|
||||||
let nrpages = (bitstring_length data / 8 - offset) / 4096
|
|
||||||
let data = takebits (offset * 8) data
|
|
||||||
|
|
||||||
(* Create the empty pages. They're not all the same because each
|
|
||||||
* page contains its own page_offset.
|
|
||||||
*)
|
|
||||||
let pages =
|
|
||||||
let noblock =
|
|
||||||
let seg_len = 4096 - 32 in
|
|
||||||
let zeroes = zeroes_bitstring ((seg_len - 4) * 8) in
|
|
||||||
BITSTRING {
|
|
||||||
Int32.of_int seg_len : 4*8 : littleendian;
|
|
||||||
zeroes : (seg_len - 4) * 8 : bitstring
|
|
||||||
} in
|
|
||||||
let zeroes = zeroes_bitstring (20*8) in
|
|
||||||
let rec loop page_offset i =
|
|
||||||
if i < nrpages then (
|
|
||||||
let page =
|
|
||||||
BITSTRING {
|
|
||||||
"hbin" : 4*8 : string;
|
|
||||||
Int32.of_int page_offset : 4*8 : littleendian;
|
|
||||||
4096_l : 4*8 : littleendian; (* page length *)
|
|
||||||
zeroes : 20*8 : bitstring;
|
|
||||||
noblock : (4096 - 32) * 8 : bitstring
|
|
||||||
} in
|
|
||||||
page :: loop (page_offset + 4096) (i+1)
|
|
||||||
) else []
|
|
||||||
in
|
|
||||||
loop offset 0
|
|
||||||
|
|
||||||
(* Write it. *)
|
|
||||||
let () =
|
|
||||||
let file = concat (header :: data :: pages) in
|
|
||||||
bitstring_to_file file filename
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open Bitstring
|
|
||||||
open ExtString
|
|
||||||
open Printf
|
|
||||||
open Visualizer_utils
|
|
||||||
|
|
||||||
let () =
|
|
||||||
if Array.length Sys.argv <> 3 then (
|
|
||||||
eprintf "Error: missing argument.
|
|
||||||
Usage: %s hivefile endpages
|
|
||||||
" Sys.executable_name;
|
|
||||||
exit 1
|
|
||||||
)
|
|
||||||
|
|
||||||
let filename = Sys.argv.(1)
|
|
||||||
let new_end_pages = int_of_string Sys.argv.(2)
|
|
||||||
|
|
||||||
(* Load the file. *)
|
|
||||||
let bits = bitstring_of_file filename
|
|
||||||
|
|
||||||
(* Split into header + data at the 4KB boundary. *)
|
|
||||||
let header, data = takebits (4096 * 8) bits, dropbits (4096 * 8) bits
|
|
||||||
|
|
||||||
(* Truncate the file data. *)
|
|
||||||
let data = takebits (new_end_pages * 8) data
|
|
||||||
|
|
||||||
(* Read the header fields. *)
|
|
||||||
let seq, last_modified, major, minor, unknown1, unknown2,
|
|
||||||
root_key, end_pages, unknown3, fname =
|
|
||||||
bitmatch header with
|
|
||||||
| { "regf" : 4*8 : string;
|
|
||||||
seq1 : 4*8 : littleendian;
|
|
||||||
seq2 : 4*8 : littleendian;
|
|
||||||
last_modified : 64 : bitstring;
|
|
||||||
major : 4*8 : littleendian;
|
|
||||||
minor : 4*8 : littleendian;
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
unknown2 : 4*8 : littleendian;
|
|
||||||
root_key : 4*8 : littleendian;
|
|
||||||
end_pages : 4*8 : littleendian;
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
fname : 64*8 : string;
|
|
||||||
unknownguid1 : 16*8 : bitstring;
|
|
||||||
unknownguid2 : 16*8 : bitstring;
|
|
||||||
unknown4 : 4*8 : littleendian;
|
|
||||||
unknownguid3 : 16*8 : bitstring;
|
|
||||||
unknown5 : 4*8 : string;
|
|
||||||
unknown6 : 340*8 : bitstring;
|
|
||||||
csum : 4*8
|
|
||||||
: littleendian, save_offset_to (crc_offset),
|
|
||||||
check (assert (crc_offset = 0x1fc * 8); true);
|
|
||||||
unknown7 : (0x1000-0x200)*8 : bitstring } ->
|
|
||||||
seq1, last_modified, major, minor, unknown1, unknown2,
|
|
||||||
root_key, end_pages, unknown3, fname
|
|
||||||
| {_} -> assert false
|
|
||||||
|
|
||||||
(* Create a new header, with endpages updated. *)
|
|
||||||
let header =
|
|
||||||
let zeroguid = zeroes_bitstring (16*8) in
|
|
||||||
let before_csum =
|
|
||||||
BITSTRING {
|
|
||||||
"regf" : 4*8 : string;
|
|
||||||
seq : 4*8 : littleendian;
|
|
||||||
seq : 4*8 : littleendian;
|
|
||||||
last_modified : 64 : bitstring;
|
|
||||||
major : 4*8 : littleendian;
|
|
||||||
minor : 4*8 : littleendian;
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
unknown2 : 4*8 : littleendian;
|
|
||||||
root_key : 4*8 : littleendian;
|
|
||||||
Int32.of_int new_end_pages : 4*8 : littleendian;
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
fname : 64*8 : string;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
0_l : 4*8 : littleendian;
|
|
||||||
zeroguid : 16*8 : bitstring;
|
|
||||||
0_l : 4*8 : littleendian;
|
|
||||||
zeroes_bitstring (340*8) : 340*8 : bitstring
|
|
||||||
} in
|
|
||||||
assert (bitstring_length before_csum = 0x1fc * 8);
|
|
||||||
let csum = bitstring_fold_left_int32_le Int32.logxor 0_l before_csum in
|
|
||||||
let csum_and_after =
|
|
||||||
BITSTRING {
|
|
||||||
csum : 4*8 : littleendian;
|
|
||||||
zeroes_bitstring ((0x1000-0x200)*8) : (0x1000-0x200)*8 : bitstring
|
|
||||||
} in
|
|
||||||
let new_header = concat [before_csum; csum_and_after] in
|
|
||||||
assert (bitstring_length header = bitstring_length new_header);
|
|
||||||
new_header
|
|
||||||
|
|
||||||
(* Write it. *)
|
|
||||||
let () =
|
|
||||||
let file = concat [header; data] in
|
|
||||||
bitstring_to_file file filename
|
|
||||||
@@ -1,984 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* For existing information on the registry format, please refer
|
|
||||||
* to the following documents. Note they are both incomplete
|
|
||||||
* and inaccurate in some respects.
|
|
||||||
*
|
|
||||||
* http://www.sentinelchicken.com/data/TheWindowsNTRegistryFileFormat.pdf
|
|
||||||
* http://pogostick.net/~pnh/ntpasswd/WinReg.txt
|
|
||||||
*)
|
|
||||||
|
|
||||||
open Bitstring
|
|
||||||
open ExtString
|
|
||||||
open Printf
|
|
||||||
open Visualizer_utils
|
|
||||||
open Visualizer_NT_time
|
|
||||||
|
|
||||||
let () =
|
|
||||||
if Array.length Sys.argv <> 2 then (
|
|
||||||
eprintf "Error: missing argument.
|
|
||||||
Usage: %s hivefile > out
|
|
||||||
where
|
|
||||||
'hivefile' is the input hive file from a Windows machine
|
|
||||||
'out' is an output file where we will write all the keys,
|
|
||||||
values etc for extended debugging purposes.
|
|
||||||
Errors, inconsistencies and unexpected fields in the hive file
|
|
||||||
are written to stderr.
|
|
||||||
" Sys.executable_name;
|
|
||||||
exit 1
|
|
||||||
)
|
|
||||||
|
|
||||||
let filename = Sys.argv.(1)
|
|
||||||
let basename = Filename.basename filename
|
|
||||||
|
|
||||||
(* Load the file. *)
|
|
||||||
let bits = bitstring_of_file filename
|
|
||||||
|
|
||||||
(* Split into header + data at the 4KB boundary. *)
|
|
||||||
let header, data = takebits (4096 * 8) bits, dropbits (4096 * 8) bits
|
|
||||||
|
|
||||||
(* Define a persistent pattern which matches the header fields. By
|
|
||||||
* using persistent patterns, we can reuse them later in the
|
|
||||||
* program.
|
|
||||||
*)
|
|
||||||
let bitmatch header_fields =
|
|
||||||
{ "regf" : 4*8 : string;
|
|
||||||
seq1 : 4*8 : littleendian;
|
|
||||||
seq2 : 4*8 : littleendian;
|
|
||||||
last_modified : 64
|
|
||||||
: littleendian, bind (nt_to_time_t last_modified);
|
|
||||||
major : 4*8 : littleendian;
|
|
||||||
minor : 4*8 : littleendian;
|
|
||||||
|
|
||||||
(* "Type". Contains 0. *)
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
|
|
||||||
(* "Format". Contains 1. *)
|
|
||||||
unknown2 : 4*8 : littleendian;
|
|
||||||
|
|
||||||
root_key : 4*8
|
|
||||||
: littleendian, bind (get_offset root_key);
|
|
||||||
end_pages : 4*8
|
|
||||||
: littleendian, bind (get_offset end_pages);
|
|
||||||
|
|
||||||
(* "Cluster". Contains 1. *)
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
|
|
||||||
filename : 64*8 : string;
|
|
||||||
|
|
||||||
(* All three GUIDs here confirmed in Windows 7 registries. In
|
|
||||||
* Windows <= 2003 these GUID fields seem to contain junk.
|
|
||||||
*
|
|
||||||
* If you write zeroes to the GUID fields, load and unload in Win7
|
|
||||||
* REGEDIT, then Windows 7 writes some random GUIDs.
|
|
||||||
*
|
|
||||||
* Also (on Win7) unknownguid1 == unknownguid2. unknownguid3 is
|
|
||||||
* different.
|
|
||||||
*)
|
|
||||||
unknownguid1 : 16*8 : bitstring;
|
|
||||||
unknownguid2 : 16*8 : bitstring;
|
|
||||||
|
|
||||||
(* Wrote zero to unknown4, loaded and unloaded it in Win7 REGEDIT,
|
|
||||||
* and it still contained zero. In existing registries it seems to
|
|
||||||
* contain random junk.
|
|
||||||
*)
|
|
||||||
unknown4 : 4*8 : littleendian;
|
|
||||||
unknownguid3 : 16*8 : bitstring;
|
|
||||||
|
|
||||||
(* If you write zero to unknown5, load and unload it in REGEDIT,
|
|
||||||
* Windows 7 puts the string "rmtm" here. Existing registries also
|
|
||||||
* seen containing this string. However on older Windows it can
|
|
||||||
* be all zeroes.
|
|
||||||
*)
|
|
||||||
unknown5 : 4*8 : string;
|
|
||||||
|
|
||||||
(* This seems to contain junk from other parts of the registry. I
|
|
||||||
* wrote zeroes here, loaded and unloaded it in Win7 REGEDIT, and
|
|
||||||
* it still contained zeroes.
|
|
||||||
*)
|
|
||||||
unknown6 : 340*8 : bitstring;
|
|
||||||
csum : 4*8
|
|
||||||
: littleendian, save_offset_to (crc_offset),
|
|
||||||
check (assert (crc_offset = 0x1fc * 8); true);
|
|
||||||
unknown7 : (0x1000-0x200)*8 : bitstring }
|
|
||||||
|
|
||||||
let fprintf_header chan bits =
|
|
||||||
bitmatch bits with
|
|
||||||
| { :header_fields } ->
|
|
||||||
fprintf chan
|
|
||||||
"HD %6ld %6ld %s %ld.%ld %08lx %08lx %s %s %08lx %s %s %s %08lx %s %s %s %08lx %s\n"
|
|
||||||
seq1 seq2 (print_time last_modified) major minor
|
|
||||||
unknown1 unknown2
|
|
||||||
(print_offset root_key) (print_offset end_pages)
|
|
||||||
unknown3 (print_utf16 filename)
|
|
||||||
(print_guid unknownguid1) (print_guid unknownguid2)
|
|
||||||
unknown4 (print_guid unknownguid3) unknown5
|
|
||||||
(print_bitstring unknown6)
|
|
||||||
csum (print_bitstring unknown7)
|
|
||||||
|
|
||||||
(* Parse the header and check it. *)
|
|
||||||
let root_key, end_pages =
|
|
||||||
bitmatch header with
|
|
||||||
| { :header_fields } ->
|
|
||||||
fprintf_header stdout header;
|
|
||||||
|
|
||||||
if major <> 1_l then
|
|
||||||
eprintf "HD hive file major <> 1 (major.minor = %ld.%ld)\n"
|
|
||||||
major minor;
|
|
||||||
if seq1 <> seq2 then
|
|
||||||
eprintf "HD hive file sequence numbers should match (%ld <> %ld)\n"
|
|
||||||
seq1 seq2;
|
|
||||||
if unknown1 <> 0_l then
|
|
||||||
eprintf "HD unknown1 field <> 0 (%08lx)\n" unknown1;
|
|
||||||
if unknown2 <> 1_l then
|
|
||||||
eprintf "HD unknown2 field <> 1 (%08lx)\n" unknown2;
|
|
||||||
if unknown3 <> 1_l then
|
|
||||||
eprintf "HD unknown3 field <> 1 (%08lx)\n" unknown3;
|
|
||||||
if not (equals unknownguid1 unknownguid2) then
|
|
||||||
eprintf "HD unknownguid1 <> unknownguid2 (%s, %s)\n"
|
|
||||||
(print_guid unknownguid1) (print_guid unknownguid2);
|
|
||||||
(* We think this is junk.
|
|
||||||
if unknown4 <> 0_l then
|
|
||||||
eprintf "HD unknown4 field <> 0 (%08lx)\n" unknown4;
|
|
||||||
*)
|
|
||||||
if unknown5 <> "rmtm" && unknown5 <> "\000\000\000\000" then
|
|
||||||
eprintf "HD unknown5 field <> \"rmtm\" & <> zeroes (%s)\n" unknown5;
|
|
||||||
(* We think this is junk.
|
|
||||||
if not (is_zero_bitstring unknown6) then
|
|
||||||
eprintf "HD unknown6 area is not zero (%s)\n"
|
|
||||||
(print_bitstring unknown6);
|
|
||||||
*)
|
|
||||||
if not (is_zero_bitstring unknown7) then
|
|
||||||
eprintf "HD unknown7 area is not zero (%s)\n"
|
|
||||||
(print_bitstring unknown7);
|
|
||||||
|
|
||||||
root_key, end_pages
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: this doesn't look like a registry hive file\n" basename
|
|
||||||
|
|
||||||
(* Define persistent patterns to match page and block fields. *)
|
|
||||||
let bitmatch page_fields =
|
|
||||||
{ "hbin" : 4*8 : string;
|
|
||||||
page_offset : 4*8
|
|
||||||
: littleendian, bind (get_offset page_offset);
|
|
||||||
page_size : 4*8
|
|
||||||
: littleendian, check (Int32.rem page_size 4096_l = 0_l),
|
|
||||||
bind (Int32.to_int page_size);
|
|
||||||
|
|
||||||
(* In the first hbin in the file these fields contain something.
|
|
||||||
* In subsequent hbins these fields are all zero.
|
|
||||||
*
|
|
||||||
* From existing hives (first hbin only):
|
|
||||||
*
|
|
||||||
* unknown1 unknown2 unknown5
|
|
||||||
* 00 00 00 00 00 00 00 00 9C 77 3B 02 6A 7D CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 50 3A 15 07 B5 9B CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 57 86 90 D4 9A 58 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 52 3F 90 9D CF 7C CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 E8 86 C1 17 BD 06 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 4A 77 CE 7A CF 7C CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 E4 EA 23 FF 69 7D CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 50 13 BA 8D A2 9A CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 0E 07 93 13 BD 06 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 9D 55 D0 B3 99 58 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 46 AC FF 8B CF 7C CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 80 29 2D 02 6A 7D CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 90 8D 36 07 B5 9B CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 5C 9B 8B B8 6A 06 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 85 9F BB 99 9A 58 CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 BE 3D 21 02 6A 7D CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 70 53 09 07 B5 9B CA 01 00 00 00 00
|
|
||||||
* 00 00 00 00 00 00 00 00 5B 62 42 B6 9A 58 CA 01 00 00 00 00
|
|
||||||
* 01 00 00 00 00 00 00 00 B2 46 9B 9E CF 7C CA 01 00 00 00 00
|
|
||||||
* 01 00 00 00 00 00 00 00 CA 88 EE 1A BD 06 CA 01 00 00 00 00
|
|
||||||
*
|
|
||||||
* From the above we worked out that fields 3 and 4 are an NT
|
|
||||||
* timestamp, which seems to be "last modified" (when REGEDIT
|
|
||||||
* unloads a hive it updates this timestamp even if nothing
|
|
||||||
* has been changed).
|
|
||||||
*)
|
|
||||||
unknown1 : 4*8 : littleendian; (* usually zero, occasionally 1 *)
|
|
||||||
unknown2 : 4*8 : littleendian; (* always zero? *)
|
|
||||||
last_modified : 64
|
|
||||||
: littleendian,
|
|
||||||
bind (if page_offset = 0 then nt_to_time_t last_modified
|
|
||||||
else (
|
|
||||||
assert (last_modified = 0_L);
|
|
||||||
0.
|
|
||||||
)
|
|
||||||
);
|
|
||||||
(* The "B.D." document said this field contains the page size, but
|
|
||||||
* this is not true. This misinformation has been copied to the
|
|
||||||
* sentinelchicken documentation too.
|
|
||||||
*)
|
|
||||||
unknown5 : 4*8 : littleendian; (* always zero? *)
|
|
||||||
|
|
||||||
(* Now the blocks in this page follow. *)
|
|
||||||
blocks : (page_size - 32) * 8 : bitstring;
|
|
||||||
|
|
||||||
rest : -1 : bitstring }
|
|
||||||
|
|
||||||
let fprintf_page chan bits =
|
|
||||||
bitmatch bits with
|
|
||||||
| { :page_fields } ->
|
|
||||||
fprintf chan "HB %s %08x %08lx %08lx %s %08lx\n"
|
|
||||||
(print_offset page_offset)
|
|
||||||
page_size unknown1 unknown2
|
|
||||||
(if page_offset = 0 then print_time last_modified
|
|
||||||
else string_of_float last_modified) unknown5
|
|
||||||
|
|
||||||
let bitmatch block_fields =
|
|
||||||
{ seg_len : 4*8
|
|
||||||
: littleendian, bind (Int32.to_int seg_len);
|
|
||||||
block_data : (abs seg_len - 4) * 8 : bitstring;
|
|
||||||
rest : -1 : bitstring }
|
|
||||||
|
|
||||||
let fprintf_block chan block_offset bits =
|
|
||||||
bitmatch bits with
|
|
||||||
| { :block_fields } ->
|
|
||||||
fprintf chan "BL %s %s %d\n"
|
|
||||||
(print_offset block_offset)
|
|
||||||
(if seg_len < 0 then "used" else "free")
|
|
||||||
(if seg_len < 0 then -seg_len else seg_len)
|
|
||||||
|
|
||||||
(* Iterate over the pages and blocks. In the process we will examine
|
|
||||||
* each page (hbin) header. Also we will build block_list which is a
|
|
||||||
* list of (block offset, length, used flag, data).
|
|
||||||
*)
|
|
||||||
let block_list = ref []
|
|
||||||
let () =
|
|
||||||
let rec loop_over_pages data data_offset =
|
|
||||||
if data_offset < end_pages then (
|
|
||||||
bitmatch data with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 -> ()
|
|
||||||
|
|
||||||
| { :page_fields } ->
|
|
||||||
fprintf_page stdout data;
|
|
||||||
|
|
||||||
assert (page_offset = data_offset);
|
|
||||||
|
|
||||||
if data_offset = 0 then ( (* first hbin only *)
|
|
||||||
if unknown1 <> 0_l then
|
|
||||||
eprintf "HB %s unknown1 field <> 0 (%08lx)\n"
|
|
||||||
(print_offset page_offset) unknown1;
|
|
||||||
if unknown2 <> 0_l then
|
|
||||||
eprintf "HB %s unknown2 field <> 0 (%08lx)\n"
|
|
||||||
(print_offset page_offset) unknown2;
|
|
||||||
if unknown5 <> 0_l then
|
|
||||||
eprintf "HB %s unknown5 field <> 0 (%08lx)\n"
|
|
||||||
(print_offset page_offset) unknown5
|
|
||||||
) else ( (* subsequent hbins *)
|
|
||||||
if unknown1 <> 0_l || unknown2 <> 0_l || unknown5 <> 0_l then
|
|
||||||
eprintf "HB %s unknown fields <> 0 (%08lx %08lx %08lx)\n"
|
|
||||||
(print_offset page_offset)
|
|
||||||
unknown1 unknown2 unknown5;
|
|
||||||
if last_modified <> 0. then
|
|
||||||
eprintf "HB %s last_modified <> 0. (%g)\n"
|
|
||||||
(print_offset page_offset) last_modified
|
|
||||||
);
|
|
||||||
|
|
||||||
(* Loop over the blocks in this page. *)
|
|
||||||
loop_over_blocks blocks (data_offset + 32);
|
|
||||||
|
|
||||||
(* Loop over rest of the pages. *)
|
|
||||||
loop_over_pages rest (data_offset + page_size)
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid hbin at offset %s\n"
|
|
||||||
basename (print_offset data_offset)
|
|
||||||
) else (
|
|
||||||
(* Reached the end of the official hbins in this file, BUT the
|
|
||||||
* file can be larger than this and might contain stuff. What
|
|
||||||
* does it contain after the hbins? We think just junk, but
|
|
||||||
* we're not sure.
|
|
||||||
*)
|
|
||||||
if not (is_zero_bitstring data) then (
|
|
||||||
eprintf "Junk in file after end of pages:\n";
|
|
||||||
let rec loop data data_offset =
|
|
||||||
bitmatch data with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 -> ()
|
|
||||||
| { :page_fields } ->
|
|
||||||
eprintf "\tjunk hbin %s 0x%08x\n"
|
|
||||||
(print_offset data_offset) page_size;
|
|
||||||
loop rest (data_offset + page_size);
|
|
||||||
| { _ } ->
|
|
||||||
eprintf "\tother junk %s %s\n"
|
|
||||||
(print_offset data_offset) (print_bitstring data)
|
|
||||||
in
|
|
||||||
loop data data_offset
|
|
||||||
)
|
|
||||||
)
|
|
||||||
and loop_over_blocks blocks block_offset =
|
|
||||||
bitmatch blocks with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 -> ()
|
|
||||||
|
|
||||||
| { :block_fields } ->
|
|
||||||
assert (block_offset mod 8 = 0);
|
|
||||||
|
|
||||||
fprintf_block stdout block_offset blocks;
|
|
||||||
|
|
||||||
let used, seg_len =
|
|
||||||
if seg_len < 0 then true, -seg_len else false, seg_len in
|
|
||||||
|
|
||||||
let block = block_offset, (seg_len, used, block_data) in
|
|
||||||
block_list := block :: !block_list;
|
|
||||||
|
|
||||||
(* Loop over the rest of the blocks in this page. *)
|
|
||||||
loop_over_blocks rest (block_offset + seg_len)
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid block near offset %s\n"
|
|
||||||
basename (print_offset block_offset)
|
|
||||||
in
|
|
||||||
loop_over_pages data 0
|
|
||||||
|
|
||||||
(* Turn the block_list into a map so we can quickly look up a block
|
|
||||||
* from its offset.
|
|
||||||
*)
|
|
||||||
let block_list = !block_list
|
|
||||||
let block_map =
|
|
||||||
List.fold_left (
|
|
||||||
fun map (block_offset, block) -> IntMap.add block_offset block map
|
|
||||||
) IntMap.empty block_list
|
|
||||||
let lookup fn offset =
|
|
||||||
try
|
|
||||||
let (_, used, _) as block = IntMap.find offset block_map in
|
|
||||||
if not used then
|
|
||||||
failwithf "%s: %s: lookup: free block %s referenced from hive tree"
|
|
||||||
basename fn (print_offset offset);
|
|
||||||
block
|
|
||||||
with Not_found ->
|
|
||||||
failwithf "%s: %s: lookup: unknown block %s referenced from hive tree"
|
|
||||||
basename fn (print_offset offset)
|
|
||||||
|
|
||||||
(* Use this to mark blocks that we've visited. If the hive contains
|
|
||||||
* no unreferenced blocks, then by the end this should just contain
|
|
||||||
* free blocks.
|
|
||||||
*)
|
|
||||||
let mark_visited, is_not_visited, unvisited_blocks =
|
|
||||||
let v = ref block_map in
|
|
||||||
let mark_visited offset = v := IntMap.remove offset !v
|
|
||||||
and is_not_visited offset = IntMap.mem offset !v
|
|
||||||
and unvisited_blocks () = !v in
|
|
||||||
mark_visited, is_not_visited, unvisited_blocks
|
|
||||||
|
|
||||||
(* Define persistent patterns to match nk-records, vk-records and
|
|
||||||
* sk-records, which are the record types that we especially want to
|
|
||||||
* analyze later. Other blocks types (eg. value lists, lf-records)
|
|
||||||
* have no "spare space" so everything is known about them and we don't
|
|
||||||
* store these.
|
|
||||||
*)
|
|
||||||
let bitmatch nk_fields =
|
|
||||||
{ "nk" : 2*8 : string;
|
|
||||||
(* Flags stored in the file as a little endian word, hence the
|
|
||||||
* unusual ordering:
|
|
||||||
*)
|
|
||||||
virtmirrored : 1;
|
|
||||||
predefinedhandle : 1; keynameascii : 1; symlinkkey : 1;
|
|
||||||
cannotbedeleted : 1; isroot : 1; ismountpoint : 1; isvolatile : 1;
|
|
||||||
unknownflag8000 : 1; unknownflag4000 : 1;
|
|
||||||
unknownflag2000 : 1; unknownflag1000 : 1;
|
|
||||||
unknownflag0800 : 1; unknownflag0400 : 1;
|
|
||||||
virtualstore : 1; virttarget : 1;
|
|
||||||
timestamp : 64 : littleendian, bind (nt_to_time_t timestamp);
|
|
||||||
unknown1 : 4*8 : littleendian;
|
|
||||||
parent : 4*8 : littleendian, bind (get_offset parent);
|
|
||||||
nr_subkeys : 4*8 : littleendian, bind (Int32.to_int nr_subkeys);
|
|
||||||
nr_subkeys_vol : 4*8;
|
|
||||||
subkeys : 4*8 : littleendian, bind (get_offset subkeys);
|
|
||||||
subkeys_vol : 4*8;
|
|
||||||
nr_values : 4*8 : littleendian, bind (Int32.to_int nr_values);
|
|
||||||
vallist : 4*8 : littleendian, bind (get_offset vallist);
|
|
||||||
sk : 4*8 : littleendian, bind (get_offset sk);
|
|
||||||
classname : 4*8 : littleendian, bind (get_offset classname);
|
|
||||||
(* sentinelchicken.com says this is a single 32 bit field
|
|
||||||
* containing maximum number of bytes in a subkey name, however
|
|
||||||
* that does not seem to be correct. We think it is several
|
|
||||||
* fields, the first being the maximum number of bytes in the
|
|
||||||
* UTF16-LE encoded version of the subkey names, (since subkey
|
|
||||||
* names are usually ASCII, that would be max length of names * 2).
|
|
||||||
* This is a historical maximum, so it can be greater than the
|
|
||||||
* current maximum name field.
|
|
||||||
*
|
|
||||||
* The remaining fields are often non-zero, but the purpose is
|
|
||||||
* unknown.
|
|
||||||
*
|
|
||||||
* In the hives we examined the other fields had values as
|
|
||||||
* follows:
|
|
||||||
* userflags: 0, 2, 0xa, 0xe
|
|
||||||
* virtcontrolflags: 0, 1
|
|
||||||
* debug: always 0
|
|
||||||
*)
|
|
||||||
max_subkey_name_len : 2*8 : littleendian;
|
|
||||||
unknown2_userflags : 4;
|
|
||||||
unknown2_virtcontrolflags : 4;
|
|
||||||
unknown2_debug : 8;
|
|
||||||
|
|
||||||
(* sentinelchicken.com says: maximum subkey CLASSNAME length,
|
|
||||||
* however that does not seem to be correct. In hives I looked
|
|
||||||
* at, it has value 0, 0xc, 0x10, 0x18, 0x1a, 0x28.
|
|
||||||
*)
|
|
||||||
unknown3 : 4*8 : littleendian;
|
|
||||||
(* sentinelchicken.com says: maximum number of bytes in a value
|
|
||||||
* name, however that does not seem to be correct. We think it is
|
|
||||||
* the maximum number of bytes in the UTF16-LE encoded version of
|
|
||||||
* the value names (since value names are usually ASCII, that would
|
|
||||||
* be max length of names * 2). This is a historical maximum, so
|
|
||||||
* it can be greater than the current maximum name field.
|
|
||||||
*)
|
|
||||||
max_vk_name_len : 4*8 : littleendian, bind (Int32.to_int max_vk_name_len);
|
|
||||||
(* sentinelchicken.com says: maximum value data size, and this
|
|
||||||
* agrees with my observations. It is the largest data size (not
|
|
||||||
* seg_len, but vk.data_len) for any value in this key. We think
|
|
||||||
* that this field is a historical max, so eg if a maximally sized
|
|
||||||
* value is deleted then this field is not reduced. Certainly
|
|
||||||
* max_vk_data_len >= the measured maximum in all the hives that we
|
|
||||||
* have observed.
|
|
||||||
*)
|
|
||||||
max_vk_data_len : 4*8 : littleendian, bind (Int32.to_int max_vk_data_len);
|
|
||||||
unknown6 : 4*8 : littleendian;
|
|
||||||
name_len : 2*8 : littleendian;
|
|
||||||
classname_len : 2*8 : littleendian;
|
|
||||||
name : name_len * 8 : string }
|
|
||||||
|
|
||||||
let fprintf_nk chan nk =
|
|
||||||
let (_, _, bits) = lookup "fprintf_nk" nk in
|
|
||||||
bitmatch bits with
|
|
||||||
| { :nk_fields } ->
|
|
||||||
fprintf chan
|
|
||||||
"NK %s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s %s %08lx %s %d %ld %s %08lx %d %s %s %s %d %x %x %x %08lx %d %d %08lx %d %d %s\n"
|
|
||||||
(print_offset nk)
|
|
||||||
(if unknownflag8000 then "8" else ".")
|
|
||||||
(if unknownflag4000 then "4" else ".")
|
|
||||||
(if unknownflag2000 then "2" else ".")
|
|
||||||
(if unknownflag1000 then "1" else ".")
|
|
||||||
(if unknownflag0800 then "8" else ".")
|
|
||||||
(if unknownflag0400 then "4" else ".")
|
|
||||||
(if virtualstore then "s" else ".")
|
|
||||||
(if virttarget then "t" else ".")
|
|
||||||
(if virtmirrored then "m" else ".")
|
|
||||||
(if predefinedhandle then "P" else ".")
|
|
||||||
(if keynameascii then "A" else ".")
|
|
||||||
(if symlinkkey then "S" else ".")
|
|
||||||
(if cannotbedeleted then "N" else ".")
|
|
||||||
(if isroot then "R" else ".")
|
|
||||||
(if ismountpoint then "M" else ".")
|
|
||||||
(if isvolatile then "V" else ".")
|
|
||||||
(print_time timestamp)
|
|
||||||
unknown1 (print_offset parent) nr_subkeys nr_subkeys_vol
|
|
||||||
(print_offset subkeys) subkeys_vol
|
|
||||||
nr_values (print_offset vallist)
|
|
||||||
(print_offset sk) (print_offset classname)
|
|
||||||
max_subkey_name_len
|
|
||||||
unknown2_userflags unknown2_virtcontrolflags unknown2_debug
|
|
||||||
unknown3 max_vk_name_len max_vk_data_len unknown6
|
|
||||||
name_len classname_len name
|
|
||||||
|
|
||||||
type data_t = Inline of bitstring | Offset of int
|
|
||||||
let bitmatch vk_fields =
|
|
||||||
{ "vk" : 2*8 : string;
|
|
||||||
name_len : 2*8 : littleendian;
|
|
||||||
(* Top bit set means that the data is stored inline. In that case
|
|
||||||
* the data length must be <= 4. The length can also be 0 (or
|
|
||||||
* 0x80000000) if the data type is NONE.
|
|
||||||
*)
|
|
||||||
data_len : 4*8
|
|
||||||
: littleendian, bind (
|
|
||||||
let is_inline = Int32.logand data_len 0x8000_0000_l = 0x8000_0000_l in
|
|
||||||
let data_len = Int32.to_int (Int32.logand data_len 0x7fff_ffff_l) in
|
|
||||||
if is_inline then assert (data_len <= 4) else assert (data_len > 4);
|
|
||||||
is_inline, data_len
|
|
||||||
);
|
|
||||||
(* The data itself depends on the type field.
|
|
||||||
*
|
|
||||||
* For REG_SZ type, the data always seems to be NUL-terminated, which
|
|
||||||
* means because these strings are often UTF-16LE, that the string will
|
|
||||||
* end with \0\0 bytes. The termination bytes are included in data_len.
|
|
||||||
*
|
|
||||||
* For REG_MULTI_SZ, see
|
|
||||||
* http://blogs.msdn.com/oldnewthing/archive/2009/10/08/9904646.aspx
|
|
||||||
*)
|
|
||||||
data : 4*8
|
|
||||||
: bitstring, bind (
|
|
||||||
let is_inline, data_len = data_len in
|
|
||||||
if is_inline then
|
|
||||||
Inline (takebits (data_len*8) data)
|
|
||||||
else (
|
|
||||||
let offset =
|
|
||||||
bitmatch data with { offset : 4*8 : littleendian } -> offset in
|
|
||||||
let offset = get_offset offset in
|
|
||||||
Offset offset
|
|
||||||
)
|
|
||||||
);
|
|
||||||
t : 4*8 : littleendian, bind (Int32.to_int t);
|
|
||||||
(* Flags, stored as a little-endian word: *)
|
|
||||||
unknown1 : 7;
|
|
||||||
nameisascii : 1; (* Clear for default [zero-length] name, always set
|
|
||||||
* otherwise in registries that we found. Perhaps this
|
|
||||||
* is really "nameisdefault" flag?
|
|
||||||
*)
|
|
||||||
unknown2 : 8;
|
|
||||||
(* Unknown field, usually contains something. *)
|
|
||||||
unknown3 : 2*8 : littleendian;
|
|
||||||
name : name_len * 8 : string }
|
|
||||||
|
|
||||||
let fprintf_vk chan vk =
|
|
||||||
let (_, _, bits) = lookup "fprintf_vk" vk in
|
|
||||||
bitmatch bits with
|
|
||||||
| { :vk_fields } ->
|
|
||||||
let real_data =
|
|
||||||
match data with
|
|
||||||
| Inline data -> data
|
|
||||||
| Offset offset ->
|
|
||||||
let (_, _, bits) = lookup "fprintf_vk (data)" offset in
|
|
||||||
bits in
|
|
||||||
let is_inline, data_len = data_len in
|
|
||||||
fprintf chan "VK %s %s %s %d %s%s %s %08x %s %08x %08x\n"
|
|
||||||
(print_offset vk)
|
|
||||||
name (if is_inline then "inline" else "-") data_len
|
|
||||||
(match data with
|
|
||||||
| Inline _ -> ""
|
|
||||||
| Offset offset -> "["^print_offset offset^"]")
|
|
||||||
(print_bitstring real_data)
|
|
||||||
(print_vk_type t)
|
|
||||||
unknown1 (if nameisascii then "A" else "L")
|
|
||||||
unknown2 unknown3
|
|
||||||
|
|
||||||
let bitmatch sk_fields =
|
|
||||||
{ "sk" : 2*8 : string;
|
|
||||||
unknown1 : 2*8 : littleendian;
|
|
||||||
sk_next : 4*8 : littleendian, bind (get_offset sk_next);
|
|
||||||
sk_prev : 4*8 : littleendian, bind (get_offset sk_prev);
|
|
||||||
refcount : 4*8 : littleendian, bind (Int32.to_int refcount);
|
|
||||||
sec_len : 4*8 : littleendian, bind (Int32.to_int sec_len);
|
|
||||||
sec_desc : sec_len * 8 : bitstring }
|
|
||||||
|
|
||||||
let fprintf_sk chan sk =
|
|
||||||
let (_, _, bits) = lookup "fprintf_sk" sk in
|
|
||||||
bitmatch bits with
|
|
||||||
| { :sk_fields } ->
|
|
||||||
fprintf chan "SK %s %04x %s %s %d %d\n"
|
|
||||||
(print_offset sk) unknown1
|
|
||||||
(print_offset sk_next) (print_offset sk_prev)
|
|
||||||
refcount sec_len
|
|
||||||
(* print_bitstring sec_desc -- suppress this *)
|
|
||||||
|
|
||||||
(* Store lists of records we encounter (lists of offsets). *)
|
|
||||||
let nk_records = ref []
|
|
||||||
and vk_records = ref []
|
|
||||||
and sk_records = ref []
|
|
||||||
|
|
||||||
(* Functions to visit each block, starting at the root. Each block
|
|
||||||
* that we visit is printed.
|
|
||||||
*)
|
|
||||||
let rec visit_nk ?(nk_is_root = false) nk =
|
|
||||||
let (_, _, bits) = lookup "visit_nk" nk in
|
|
||||||
mark_visited nk;
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :nk_fields } ->
|
|
||||||
fprintf_nk stdout nk;
|
|
||||||
|
|
||||||
nk_records := nk :: !nk_records;
|
|
||||||
|
|
||||||
(* Check the isroot flag is only set on the root node. *)
|
|
||||||
assert (isroot = nk_is_root);
|
|
||||||
|
|
||||||
if unknownflag8000 then
|
|
||||||
eprintf "NK %s unknownflag8000 is set\n" (print_offset nk);
|
|
||||||
if unknownflag4000 then
|
|
||||||
eprintf "NK %s unknownflag4000 is set\n" (print_offset nk);
|
|
||||||
if unknownflag2000 then
|
|
||||||
eprintf "NK %s unknownflag2000 is set\n" (print_offset nk);
|
|
||||||
if unknownflag1000 then
|
|
||||||
eprintf "NK %s unknownflag1000 is set\n" (print_offset nk);
|
|
||||||
if unknownflag0800 then
|
|
||||||
eprintf "NK %s unknownflag0800 is set\n" (print_offset nk);
|
|
||||||
if unknownflag0400 then
|
|
||||||
eprintf "NK %s unknownflag0400 is set\n" (print_offset nk);
|
|
||||||
if unknown1 <> 0_l then
|
|
||||||
eprintf "NK %s unknown1 <> 0 (%08lx)\n" (print_offset nk) unknown1;
|
|
||||||
if unknown2_userflags <> 0 then
|
|
||||||
eprintf "NK %s unknown2_userflags <> 0 (%x)\n"
|
|
||||||
(print_offset nk) unknown2_userflags;
|
|
||||||
if unknown2_virtcontrolflags <> 0 then
|
|
||||||
eprintf "NK %s unknown2_virtcontrolflags <> 0 (%x)\n"
|
|
||||||
(print_offset nk) unknown2_virtcontrolflags;
|
|
||||||
if unknown2_debug <> 0 then
|
|
||||||
eprintf "NK %s unknown2_debug <> 0 (%x)\n"
|
|
||||||
(print_offset nk) unknown2_debug;
|
|
||||||
if unknown3 <> 0_l then
|
|
||||||
eprintf "NK %s unknown3 <> 0 (%08lx)\n" (print_offset nk) unknown3;
|
|
||||||
if unknown6 <> 0_l then
|
|
||||||
eprintf "NK %s unknown6 <> 0 (%08lx)\n" (print_offset nk) unknown6;
|
|
||||||
|
|
||||||
(* -- common, assume it's not an error
|
|
||||||
if classname = -1 then
|
|
||||||
eprintf "NK %s has no classname\n" (print_offset nk);
|
|
||||||
if classname_len = 0 then
|
|
||||||
eprintf "NK %s has zero-length classname\n" (print_offset nk);
|
|
||||||
*)
|
|
||||||
if sk = -1 then
|
|
||||||
eprintf "NK %s has no sk-record\n" (print_offset nk);
|
|
||||||
if name_len = 0 then
|
|
||||||
eprintf "NK %s has zero-length name\n" (print_offset nk);
|
|
||||||
|
|
||||||
(* Visit the values first at this node. *)
|
|
||||||
let max_data_len, max_name_len =
|
|
||||||
if vallist <> -1 then
|
|
||||||
visit_vallist nr_values vallist
|
|
||||||
else
|
|
||||||
0, 0 in
|
|
||||||
|
|
||||||
if max_vk_data_len < max_data_len then
|
|
||||||
eprintf "NK %s nk.max_vk_data_len (%d) < actual max data_len (%d)\n"
|
|
||||||
(print_offset nk) max_vk_data_len max_data_len;
|
|
||||||
|
|
||||||
if max_vk_name_len < max_name_len * 2 then
|
|
||||||
eprintf "NK %s nk.max_vk_name_len (%d) < actual max name_len * 2 (%d)\n"
|
|
||||||
(print_offset nk) max_vk_name_len (max_name_len * 2);
|
|
||||||
|
|
||||||
(* Visit the subkeys of this node. *)
|
|
||||||
if subkeys <> -1 then (
|
|
||||||
let counted, max_name_len, _ = visit_subkeys subkeys in
|
|
||||||
|
|
||||||
if counted <> nr_subkeys then
|
|
||||||
failwithf "%s: incorrect count of subkeys (%d, counted %d) in subkey list at %s\n"
|
|
||||||
basename nr_subkeys counted (print_offset subkeys);
|
|
||||||
|
|
||||||
if max_subkey_name_len < max_name_len * 2 then
|
|
||||||
eprintf "NK %s nk.max_subkey_name_len (%d) < actual max name_len * 2 (%d)\n"
|
|
||||||
(print_offset nk) max_subkey_name_len (max_name_len * 2);
|
|
||||||
);
|
|
||||||
|
|
||||||
(* Visit the sk-record and classname. *)
|
|
||||||
if sk <> -1 then
|
|
||||||
visit_sk sk;
|
|
||||||
if classname <> -1 then
|
|
||||||
visit_classname classname classname_len;
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid nk block at offset %s\n"
|
|
||||||
basename (print_offset nk)
|
|
||||||
)
|
|
||||||
|
|
||||||
and visit_vallist nr_values vallist =
|
|
||||||
let (seg_len, _, bits) = lookup "visit_vallist" vallist in
|
|
||||||
mark_visited vallist;
|
|
||||||
printf "VL %s %d %d\n" (print_offset vallist) nr_values seg_len;
|
|
||||||
visit_values_in_vallist nr_values vallist bits
|
|
||||||
|
|
||||||
and visit_values_in_vallist nr_values vallist bits =
|
|
||||||
if nr_values > 0 then (
|
|
||||||
bitmatch bits with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 ->
|
|
||||||
assert (nr_values = 0);
|
|
||||||
0, 0
|
|
||||||
|
|
||||||
| { value : 4*8 : littleendian, bind (get_offset value);
|
|
||||||
rest : -1 : bitstring } ->
|
|
||||||
let data_len, name_len = visit_vk value in
|
|
||||||
let max_data_len, max_name_len =
|
|
||||||
visit_values_in_vallist (nr_values-1) vallist rest in
|
|
||||||
max max_data_len data_len, max max_name_len name_len
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid offset in value list at %s\n"
|
|
||||||
basename (print_offset vallist)
|
|
||||||
) else 0, 0
|
|
||||||
|
|
||||||
and visit_vk vk =
|
|
||||||
let (_, _, bits) = lookup "visit_vk" vk in
|
|
||||||
mark_visited vk;
|
|
||||||
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :vk_fields } ->
|
|
||||||
fprintf_vk stdout vk;
|
|
||||||
|
|
||||||
let is_inline, data_len = data_len in
|
|
||||||
|
|
||||||
if unknown1 <> 0 then
|
|
||||||
eprintf "VK %s unknown1 flags set (%02x)\n"
|
|
||||||
(print_offset vk) unknown1;
|
|
||||||
if unknown2 <> 0 then
|
|
||||||
eprintf "VK %s unknown2 flags set (%02x)\n"
|
|
||||||
(print_offset vk) unknown2;
|
|
||||||
if unknown3 <> 0 then
|
|
||||||
eprintf "VK %s unknown3 flags set (%04x)\n"
|
|
||||||
(print_offset vk) unknown3;
|
|
||||||
|
|
||||||
(* Note this is common for default [ie. zero-length] key names. *)
|
|
||||||
if not nameisascii && name_len > 0 then
|
|
||||||
eprintf "VK %s has non-ASCII name flag set (name is %s)\n"
|
|
||||||
(print_offset vk) (print_binary_string name);
|
|
||||||
|
|
||||||
vk_records := vk :: !vk_records;
|
|
||||||
(match data with
|
|
||||||
| Inline data -> ()
|
|
||||||
| Offset offset ->
|
|
||||||
let _ = lookup "visit_vk (data)" offset in
|
|
||||||
mark_visited offset
|
|
||||||
);
|
|
||||||
|
|
||||||
data_len, name_len
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid vk block at offset %s\n"
|
|
||||||
basename (print_offset vk)
|
|
||||||
)
|
|
||||||
|
|
||||||
(* Visits subkeys, recursing through intermediate lf/lh/ri structures,
|
|
||||||
* and returns the number of subkeys actually seen.
|
|
||||||
*)
|
|
||||||
and visit_subkeys subkeys =
|
|
||||||
let (_, _, bits) = lookup "visit_subkeys" subkeys in
|
|
||||||
mark_visited subkeys;
|
|
||||||
(bitmatch bits with
|
|
||||||
| { "lf" : 2*8 : string;
|
|
||||||
len : 2*8 : littleendian; (* number of subkeys of this node *)
|
|
||||||
rest : len*8*8 : bitstring } ->
|
|
||||||
printf "LF %s %d\n" (print_offset subkeys) len;
|
|
||||||
visit_subkeys_in_lf_list false subkeys len rest
|
|
||||||
|
|
||||||
| { "lh" : 2*8 : string;
|
|
||||||
len : 2*8 : littleendian; (* number of subkeys of this node *)
|
|
||||||
rest : len*8*8 : bitstring } ->
|
|
||||||
printf "LF %s %d\n" (print_offset subkeys) len;
|
|
||||||
visit_subkeys_in_lf_list true subkeys len rest
|
|
||||||
|
|
||||||
| { "ri" : 2*8 : string;
|
|
||||||
len : 2*8 : littleendian;
|
|
||||||
rest : len*4*8 : bitstring } ->
|
|
||||||
printf "RI %s %d\n" (print_offset subkeys) len;
|
|
||||||
visit_subkeys_in_ri_list subkeys len rest
|
|
||||||
|
|
||||||
(* In theory you can have an li-record here, but we've never
|
|
||||||
* seen one.
|
|
||||||
*)
|
|
||||||
|
|
||||||
| { "nk" : 2*8 : string } ->
|
|
||||||
visit_nk subkeys;
|
|
||||||
let name, name_len = name_of_nk subkeys in
|
|
||||||
1, name_len, name
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid subkey node found at %s\n"
|
|
||||||
basename (print_offset subkeys)
|
|
||||||
)
|
|
||||||
|
|
||||||
and visit_subkeys_in_lf_list newstyle_hash subkeys_top len bits =
|
|
||||||
if len > 0 then (
|
|
||||||
bitmatch bits with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 ->
|
|
||||||
assert (len = 0);
|
|
||||||
0, 0, ""
|
|
||||||
|
|
||||||
| { offset : 4*8 : littleendian, bind (get_offset offset);
|
|
||||||
hash : 4*8 : bitstring;
|
|
||||||
rest : -1 : bitstring } ->
|
|
||||||
let c1, name_len1, name = visit_subkeys offset in
|
|
||||||
|
|
||||||
check_hash offset newstyle_hash hash name;
|
|
||||||
|
|
||||||
let c2, name_len2, _ =
|
|
||||||
visit_subkeys_in_lf_list newstyle_hash subkeys_top (len-1) rest in
|
|
||||||
c1 + c2, max name_len1 name_len2, ""
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid subkey in lf/lh list at %s\n"
|
|
||||||
basename (print_offset subkeys_top)
|
|
||||||
) else 0, 0, ""
|
|
||||||
|
|
||||||
and visit_subkeys_in_ri_list subkeys_top len bits =
|
|
||||||
if len > 0 then (
|
|
||||||
bitmatch bits with
|
|
||||||
| { rest : -1 : bitstring } when bitstring_length rest = 0 ->
|
|
||||||
assert (len = 0);
|
|
||||||
0, 0, ""
|
|
||||||
|
|
||||||
| { offset : 4*8 : littleendian, bind (get_offset offset);
|
|
||||||
rest : -1 : bitstring } ->
|
|
||||||
let c1, name_len1, _ = visit_subkeys offset in
|
|
||||||
let c2, name_len2, _ =
|
|
||||||
visit_subkeys_in_ri_list subkeys_top (len-1) rest in
|
|
||||||
c1 + c2, max name_len1 name_len2, ""
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid subkey in ri list at %s\n"
|
|
||||||
basename (print_offset subkeys_top)
|
|
||||||
) else 0, 0, ""
|
|
||||||
|
|
||||||
and check_hash offset newstyle_hash hash name =
|
|
||||||
if not newstyle_hash then (
|
|
||||||
(* Old-style lf record hash the first four bytes of the name
|
|
||||||
* as the has.
|
|
||||||
*)
|
|
||||||
let len = String.length name in
|
|
||||||
let name_bits =
|
|
||||||
if len >= 4 then
|
|
||||||
bitstring_of_string (String.sub name 0 4)
|
|
||||||
else (
|
|
||||||
let zeroes = zeroes_bitstring ((4-len)*8) in
|
|
||||||
concat [bitstring_of_string name; zeroes]
|
|
||||||
) in
|
|
||||||
if not (equals hash name_bits) then
|
|
||||||
eprintf "LF incorrect hash for name %s, expected %s, actual %s\n"
|
|
||||||
name (print_bitstring name_bits) (print_bitstring hash)
|
|
||||||
) else (
|
|
||||||
(* New-style lh record has a proper hash. *)
|
|
||||||
let actual = bitmatch hash with { hash : 4*8 : littleendian } -> hash in
|
|
||||||
let h = ref 0_l in
|
|
||||||
String.iter (
|
|
||||||
fun c ->
|
|
||||||
h := Int32.mul !h 37_l;
|
|
||||||
h := Int32.add !h (Int32.of_int (Char.code (Char.uppercase c)))
|
|
||||||
) name;
|
|
||||||
if actual <> !h then
|
|
||||||
eprintf "LH incorrect hash for name %s, expected 0x%08lx, actual 0x%08lx\n"
|
|
||||||
name !h actual
|
|
||||||
)
|
|
||||||
|
|
||||||
and name_of_nk nk =
|
|
||||||
let (_, _, bits) = lookup "name_of_nk" nk in
|
|
||||||
bitmatch bits with
|
|
||||||
| { :nk_fields } -> name, name_len
|
|
||||||
|
|
||||||
and visit_sk sk =
|
|
||||||
let (_, _, bits) = lookup "visit_sk" sk in
|
|
||||||
if is_not_visited sk then (
|
|
||||||
mark_visited sk;
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :sk_fields } ->
|
|
||||||
fprintf_sk stdout sk;
|
|
||||||
|
|
||||||
if unknown1 <> 0 then
|
|
||||||
eprintf "SK %s unknown1 <> 0 (%04x)\n" (print_offset sk) unknown1;
|
|
||||||
|
|
||||||
sk_records := sk :: !sk_records
|
|
||||||
|
|
||||||
| {_} ->
|
|
||||||
failwithf "%s: invalid sk-record at %s\n"
|
|
||||||
basename (print_offset sk)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
and visit_classname classname classname_len =
|
|
||||||
let (seg_len, _, bits) = lookup "visit_classname" classname in
|
|
||||||
mark_visited classname;
|
|
||||||
assert (seg_len >= classname_len);
|
|
||||||
printf "CL %s %s\n" (print_offset classname) (print_bitstring bits)
|
|
||||||
|
|
||||||
let () =
|
|
||||||
visit_nk ~nk_is_root:true root_key
|
|
||||||
|
|
||||||
(* These are immutable now. *)
|
|
||||||
let nk_records = !nk_records
|
|
||||||
let vk_records = !vk_records
|
|
||||||
let sk_records = !sk_records
|
|
||||||
|
|
||||||
(* So we can rapidly tell what is an nk/vk/sk offset. *)
|
|
||||||
let nk_set =
|
|
||||||
List.fold_left (fun set offs -> IntSet.add offs set) IntSet.empty nk_records
|
|
||||||
let vk_set =
|
|
||||||
List.fold_left (fun set offs -> IntSet.add offs set) IntSet.empty vk_records
|
|
||||||
let sk_set =
|
|
||||||
List.fold_left (fun set offs -> IntSet.add offs set) IntSet.empty sk_records
|
|
||||||
|
|
||||||
(* Now after visiting all the blocks, are there any used blocks which
|
|
||||||
* are unvisited? If there are any then that would indicate either (a)
|
|
||||||
* that the hive contains unreferenced blocks, or (b) that there are
|
|
||||||
* referenced blocks that we did not visit because we don't have a full
|
|
||||||
* understanding of the hive format.
|
|
||||||
*
|
|
||||||
* Windows 7 registries often contain a few of these -- not clear
|
|
||||||
* how serious they are, but don't fail here.
|
|
||||||
*)
|
|
||||||
let () =
|
|
||||||
let unvisited = unvisited_blocks () in
|
|
||||||
IntMap.iter (
|
|
||||||
fun offset block ->
|
|
||||||
match block with
|
|
||||||
| (_, false, _) -> () (* ignore unused blocks *)
|
|
||||||
| (seg_len, true, _) ->
|
|
||||||
eprintf "used block %s (length %d) is not referenced\n"
|
|
||||||
(print_offset offset) seg_len
|
|
||||||
) unvisited
|
|
||||||
|
|
||||||
(* Check the SKs are:
|
|
||||||
* (a) linked into a single circular list through the sk_prev/sk_next
|
|
||||||
* pointers
|
|
||||||
* (b) refcounts are correct
|
|
||||||
*)
|
|
||||||
let () =
|
|
||||||
if List.length sk_records > 0 then (
|
|
||||||
let sk0 = List.hd sk_records in (* start at any arbitrary sk *)
|
|
||||||
(* This loop follows the chain of sk pointers until we arrive
|
|
||||||
* back at the original, checking prev/next are consistent.
|
|
||||||
*)
|
|
||||||
let rec loop visited prevsk sk =
|
|
||||||
if sk <> sk0 then (
|
|
||||||
if not (IntSet.mem sk sk_set) then
|
|
||||||
eprintf "SK %s not an sk-record (faulty sk_next somewhere)\n"
|
|
||||||
(print_offset sk)
|
|
||||||
else (
|
|
||||||
let _, _, bits = lookup "loop sk circular list" sk in
|
|
||||||
bitmatch bits with
|
|
||||||
| { :sk_fields } ->
|
|
||||||
if sk_prev <> prevsk then
|
|
||||||
eprintf "SK %s sk_prev != previous sk (%s, %s)\n"
|
|
||||||
(print_offset sk)
|
|
||||||
(print_offset sk_prev) (print_offset prevsk);
|
|
||||||
if IntSet.mem sk visited then
|
|
||||||
eprintf "SK %s already visited (bad circular list)\n"
|
|
||||||
(print_offset sk);
|
|
||||||
let visited = IntSet.add sk visited in
|
|
||||||
loop visited sk sk_next
|
|
||||||
)
|
|
||||||
)
|
|
||||||
in
|
|
||||||
let _, _, bits = lookup "start sk circular list" sk0 in
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :sk_fields } ->
|
|
||||||
loop IntSet.empty sk_prev sk0
|
|
||||||
);
|
|
||||||
|
|
||||||
(* For every nk-record, if it references an sk-record count that,
|
|
||||||
* then check this matches the refcounts in the sk-records
|
|
||||||
* themselves.
|
|
||||||
*)
|
|
||||||
let refcounts = Counter.create () in
|
|
||||||
List.iter (
|
|
||||||
fun nk ->
|
|
||||||
let _, _, bits = lookup "sk refcounter (nk)" nk in
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :nk_fields } ->
|
|
||||||
Counter.incr refcounts sk
|
|
||||||
)
|
|
||||||
) nk_records;
|
|
||||||
|
|
||||||
List.iter (
|
|
||||||
fun sk ->
|
|
||||||
let _, _, bits = lookup "sk refcounter (sk)" sk in
|
|
||||||
(bitmatch bits with
|
|
||||||
| { :sk_fields } ->
|
|
||||||
let actual = Counter.get refcounts sk in
|
|
||||||
if actual <> refcount then
|
|
||||||
eprintf "SK %s incorrect refcount (actual %d, in file %d)\n"
|
|
||||||
(print_offset sk) actual refcount
|
|
||||||
)
|
|
||||||
) sk_records
|
|
||||||
)
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* For existing information on the registry format, please refer
|
|
||||||
* to the following documents. Note they are both incomplete
|
|
||||||
* and inaccurate in some respects.
|
|
||||||
*)
|
|
||||||
|
|
||||||
(* Convert an NT file timestamp to time_t. See:
|
|
||||||
* http://blogs.msdn.com/oldnewthing/archive/2003/09/05/54806.aspx
|
|
||||||
* http://support.microsoft.com/kb/167296
|
|
||||||
*)
|
|
||||||
let nt_to_time_t t =
|
|
||||||
let t = Int64.sub t 116444736000000000L in
|
|
||||||
let t = Int64.div t 10000000L in
|
|
||||||
Int64.to_float t
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
(* Windows Registry reverse-engineering tool.
|
|
||||||
* Copyright (C) 2010 Red Hat Inc.
|
|
||||||
*
|
|
||||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* For existing information on the registry format, please refer
|
|
||||||
* to the following documents. Note they are both incomplete
|
|
||||||
* and inaccurate in some respects.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open ExtString
|
|
||||||
open Printf
|
|
||||||
|
|
||||||
let failwithf fs = ksprintf failwith fs
|
|
||||||
|
|
||||||
(* Useful function to convert unknown bitstring fragments into
|
|
||||||
* printable strings.
|
|
||||||
*)
|
|
||||||
let rec print_bitstring bits =
|
|
||||||
let str = Bitstring.string_of_bitstring bits in
|
|
||||||
print_binary_string str
|
|
||||||
and print_binary_string str =
|
|
||||||
let rec printable = function
|
|
||||||
| '\x00' -> "\\0" | '\x01' -> "\\1" | '\x02' -> "\\2" | '\x03' -> "\\3"
|
|
||||||
| '\x04' -> "\\4" | '\x05' -> "\\5" | '\x06' -> "\\6" | '\x07' -> "\\7"
|
|
||||||
| ('\x08'..'\x31' as c)
|
|
||||||
| ('\x7f'..'\xff' as c) -> sprintf "\\x%02x" (Char.code c)
|
|
||||||
| ('\x32'..'\x7e' as c) -> String.make 1 c
|
|
||||||
and repeat str = function
|
|
||||||
| n when n <= 0 -> ""
|
|
||||||
| n -> str ^ repeat str (n-1)
|
|
||||||
in
|
|
||||||
let chars = String.explode str in
|
|
||||||
let rec loop acc = function
|
|
||||||
| [] -> List.rev acc
|
|
||||||
| x :: xs ->
|
|
||||||
let rec loop2 i = function
|
|
||||||
| y :: ys when x = y -> loop2 (i+1) ys
|
|
||||||
| ys -> i, ys
|
|
||||||
in
|
|
||||||
let count, ys = loop2 1 xs in
|
|
||||||
let acc = (count, x) :: acc in
|
|
||||||
loop acc ys
|
|
||||||
in
|
|
||||||
let frags = loop [] chars in
|
|
||||||
let frags =
|
|
||||||
List.map (function
|
|
||||||
| (nr, x) when nr <= 4 -> repeat (printable x) nr
|
|
||||||
| (nr, x) -> sprintf "%s<%d times>" (printable x) nr
|
|
||||||
) frags in
|
|
||||||
"\"" ^ String.concat "" frags ^ "\""
|
|
||||||
|
|
||||||
(* Convert an offset from the file to an offset. The only special
|
|
||||||
* thing is that 0xffffffff in the file is used as a kind of "NULL
|
|
||||||
* pointer". We map these null values to -1.
|
|
||||||
*)
|
|
||||||
let get_offset = function
|
|
||||||
| 0xffffffff_l -> -1
|
|
||||||
| i -> Int32.to_int i
|
|
||||||
|
|
||||||
(* Print an offset. *)
|
|
||||||
let print_offset = function
|
|
||||||
| -1 -> "NULL"
|
|
||||||
| i -> sprintf "@%08x" i
|
|
||||||
|
|
||||||
(* Print time. *)
|
|
||||||
let print_time t =
|
|
||||||
let tm = Unix.gmtime t in
|
|
||||||
sprintf "%04d-%02d-%02d %02d:%02d:%02d"
|
|
||||||
(tm.Unix.tm_year + 1900) (tm.Unix.tm_mon + 1) tm.Unix.tm_mday
|
|
||||||
tm.Unix.tm_hour tm.Unix.tm_min tm.Unix.tm_sec
|
|
||||||
|
|
||||||
(* Print UTF16LE. *)
|
|
||||||
let print_utf16 str =
|
|
||||||
let n = String.length str in
|
|
||||||
if n land 1 <> 0 then
|
|
||||||
print_binary_string str
|
|
||||||
else (
|
|
||||||
let rec loop i =
|
|
||||||
if i < n-1 then (
|
|
||||||
let c1 = Char.code (str.[i]) in
|
|
||||||
let c2 = Char.code (str.[i+1]) in
|
|
||||||
if c1 <> 0 || c2 <> 0 then (
|
|
||||||
(* Well, this doesn't print non-7bit-ASCII ... *)
|
|
||||||
let c =
|
|
||||||
if c2 = 0 then String.make 1 (Char.chr c1)
|
|
||||||
else sprintf "\\u%04d" (c2 * 256 + c1) in
|
|
||||||
c :: loop (i+2)
|
|
||||||
) else []
|
|
||||||
) else []
|
|
||||||
in
|
|
||||||
let frags = loop 0 in
|
|
||||||
"L\"" ^ String.concat "" frags ^ "\""
|
|
||||||
)
|
|
||||||
|
|
||||||
(* A map of int -> anything. *)
|
|
||||||
module IntMap = Map.Make (struct type t = int let compare = compare end)
|
|
||||||
|
|
||||||
(* A set of ints. *)
|
|
||||||
module IntSet = Set.Make (struct type t = int let compare = compare end)
|
|
||||||
|
|
||||||
(* Print registry vk-record type field. *)
|
|
||||||
let print_vk_type = function
|
|
||||||
| 0 -> "NONE"
|
|
||||||
| 1 -> "SZ"
|
|
||||||
| 2 -> "EXPAND_SZ"
|
|
||||||
| 3 -> "BINARY"
|
|
||||||
| 4 -> "DWORD"
|
|
||||||
| 5 -> "DWORD_BIG_ENDIAN"
|
|
||||||
| 6 -> "LINK"
|
|
||||||
| 7 -> "MULTI_SZ"
|
|
||||||
| 8 -> "RESOURCE_LiST"
|
|
||||||
| 9 -> "FULL_RESOURCE_DESCRIPTOR"
|
|
||||||
| 10 -> "RESOURCE_REQUIREMENTS_LIST"
|
|
||||||
| 11 -> "QWORD"
|
|
||||||
| i -> sprintf "UNKNOWN_VK_TYPE_%d" i
|
|
||||||
|
|
||||||
(* XXX We should write a more efficient version of this and
|
|
||||||
* push it into the bitstring library.
|
|
||||||
*)
|
|
||||||
let is_zero_bitstring bits =
|
|
||||||
let len = Bitstring.bitstring_length bits in
|
|
||||||
let zeroes = Bitstring.zeroes_bitstring len in
|
|
||||||
0 = Bitstring.compare bits zeroes
|
|
||||||
|
|
||||||
let is_zero_guid = is_zero_bitstring
|
|
||||||
|
|
||||||
(* http://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx
|
|
||||||
* Endianness of GUIDs is not clear from the MSDN documentation,
|
|
||||||
* so this is just a guess.
|
|
||||||
*)
|
|
||||||
let print_guid bits =
|
|
||||||
bitmatch bits with
|
|
||||||
| { data1 : 4*8 : littleendian;
|
|
||||||
data2 : 2*8 : littleendian;
|
|
||||||
data3 : 2*8 : littleendian;
|
|
||||||
data4_1 : 2*8 : littleendian;
|
|
||||||
data4_2 : 6*8 : littleendian } ->
|
|
||||||
sprintf "%08lX-%04X-%04X-%04X-%012LX" data1 data2 data3 data4_1 data4_2
|
|
||||||
| { _ } ->
|
|
||||||
assert false
|
|
||||||
|
|
||||||
(* Fold over little-endian 32-bit integers in a bitstring. *)
|
|
||||||
let rec bitstring_fold_left_int32_le f a bits =
|
|
||||||
bitmatch bits with
|
|
||||||
| { i : 4*8 : littleendian;
|
|
||||||
rest : -1 : bitstring } ->
|
|
||||||
bitstring_fold_left_int32_le f (f a i) rest
|
|
||||||
| { rest : -1 : bitstring } when Bitstring.bitstring_length rest = 0 -> a
|
|
||||||
| { _ } ->
|
|
||||||
invalid_arg "bitstring_fold_left_int32_le: length not a multiple of 32 bits"
|
|
||||||
@@ -80,9 +80,6 @@ fish/tilde.c
|
|||||||
fish/time.c
|
fish/time.c
|
||||||
fuse/dircache.c
|
fuse/dircache.c
|
||||||
fuse/guestmount.c
|
fuse/guestmount.c
|
||||||
hivex/hivex.c
|
|
||||||
hivex/hivexml.c
|
|
||||||
hivex/hivexsh.c
|
|
||||||
inspector/virt-inspector
|
inspector/virt-inspector
|
||||||
java/com_redhat_et_libguestfs_GuestFS.c
|
java/com_redhat_et_libguestfs_GuestFS.c
|
||||||
ocaml/guestfs_c.c
|
ocaml/guestfs_c.c
|
||||||
|
|||||||
@@ -450,10 +450,10 @@ Where we can help is in resolving the case insensitivity of paths.
|
|||||||
For this, call C<guestfs_case_sensitive_path>.
|
For this, call C<guestfs_case_sensitive_path>.
|
||||||
|
|
||||||
Libguestfs also provides some help for decoding Windows Registry
|
Libguestfs also provides some help for decoding Windows Registry
|
||||||
"hive" files, through the library C<libhivex> which is part of
|
"hive" files, through the library C<hivex> which is part of the
|
||||||
libguestfs. You have to locate and download the hive file(s)
|
libguestfs project. You have to locate and download the hive file(s)
|
||||||
yourself, and then pass them to C<libhivex> functions. See also the
|
yourself, and then pass them to C<hivex> functions. See also the
|
||||||
programs L<hivexml(1)>, L<hivexget(1)> and L<virt-win-reg(1)> for more
|
programs L<hivexml(1)>, L<hivexsh(1)> and L<virt-win-reg(1)> for more
|
||||||
help on this issue.
|
help on this issue.
|
||||||
|
|
||||||
=head2 USING LIBGUESTFS WITH OTHER PROGRAMMING LANGUAGES
|
=head2 USING LIBGUESTFS WITH OTHER PROGRAMMING LANGUAGES
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ while(-l $path) {
|
|||||||
# Get the absolute path of the parent directory
|
# Get the absolute path of the parent directory
|
||||||
$path = abs_path(dirname($path).'/..');
|
$path = abs_path(dirname($path).'/..');
|
||||||
|
|
||||||
$ENV{PATH} = $path.'/hivex:'.$ENV{PATH};
|
|
||||||
$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
|
$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
|
||||||
$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
|
$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
|
||||||
$ENV{PERL5LIB} = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
|
$ENV{PERL5LIB} = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
|
||||||
|
|||||||
Reference in New Issue
Block a user