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:
Richard Jones
2010-02-22 12:53:16 +00:00
parent aa4700f032
commit a8c3723e38
39 changed files with 20 additions and 8143 deletions

9
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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

View File

@@ -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!

View File

@@ -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

View File

@@ -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.

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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_ */

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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.

File diff suppressed because it is too large Load Diff

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

Binary file not shown.

View File

@@ -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 $@

View File

@@ -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

View File

@@ -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

View File

@@ -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. *)

View File

@@ -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

View File

@@ -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

View File

@@ -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
)

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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';