You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1114 lines
29 KiB
1114 lines
29 KiB
#include "pch.h"
|
|
|
|
HANDLE g_hHeap;
|
|
HINSTANCE g_hInst;
|
|
|
|
#ifndef DEBUG
|
|
#error MemDbt must be built with DEBUG defined
|
|
#endif
|
|
|
|
#define ONEBITSET(x) ((x) && !((x) & ((x) - 1)))
|
|
|
|
typedef BOOL (WINAPI INITROUTINE_PROTOTYPE)(HINSTANCE, DWORD, LPVOID);
|
|
|
|
INITROUTINE_PROTOTYPE MigUtil_Entry;
|
|
INITROUTINE_PROTOTYPE MemDb_Entry;
|
|
INITROUTINE_PROTOTYPE FileEnum_Entry;
|
|
|
|
|
|
typedef struct {
|
|
DWORD Bit;
|
|
PCSTR Name;
|
|
} PROPNAME, *PPROPNAME;
|
|
|
|
#define DEFMAC(opbit,name,memdbname,prop_ct) {opbit,#name},
|
|
|
|
PROPNAME g_PropNames[] = {
|
|
PATH_OPERATIONS /* , */
|
|
{0, NULL}
|
|
};
|
|
|
|
|
|
VOID
|
|
HelpAndExit (
|
|
VOID
|
|
)
|
|
{
|
|
printf ("Brief Help:\n\n"
|
|
"/A All values (or export as ANSI)\n"
|
|
"/C Check internal consistency of memdb.\n"
|
|
"/D:<n> Enumeration depth\n"
|
|
"/E Dump file operation reference help.\n"
|
|
"/E:<n> List all files in operation n.\n"
|
|
"/ER:<r> Specifies export root\n"
|
|
"/EF:<f> Specifies export file\n"
|
|
"/F Find keys that have values equal to <value>\n"
|
|
"/I Import an exported file\n"
|
|
"/L:<f> List operations for file f\n"
|
|
"/N GetFileStatusOnNt for <value>\n"
|
|
"/NP GetFilePathOnNt for <value>\n"
|
|
"/O List offsets in enumeration.\n"
|
|
"/O:<n> Display key at offset n.\n"
|
|
"/P:<p> Search pattern is p.\n"
|
|
"/S Start level for enumeration.\n"
|
|
"\n"
|
|
"/?? Full Help\n"
|
|
);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
VOID
|
|
FullHelpAndExit (
|
|
VOID
|
|
)
|
|
{
|
|
printf ("Command line syntax:\n\n"
|
|
"memdbt [file] [/P:pattern] [/D:depth] [/A] [/Z] [/H] [/K]\n"
|
|
" [/F[U|A|O]:<value>] [/O]\n"
|
|
"memdbt [file] /T\n"
|
|
"memdbt [file] /O:<n> [/Z] [/K]\n"
|
|
"memdbt [file] /G:<key> [/Z] [/K]\n"
|
|
"memdbt [file] /C [/P:pattern]\n"
|
|
"memdbt [file] /$\n"
|
|
"memdbt [file] /[B|X]:<root1>,<root2> [/D:depth] [/A] [/Z] [/H] [/K]\n"
|
|
"memdbt [file] /L:<9x_file>\n"
|
|
"memdbt [file] /E:<fileop>\n"
|
|
"memdbt [file] /N[P]:<path>\n"
|
|
"memdbt [file] /ER:<root> /EF:<file> [/A]\n"
|
|
"memdbt /I:<filename> [file to update]\n"
|
|
"\n"
|
|
"/A If specified, all levels are enumerated, including those\n"
|
|
" that are not endpoints. If specified with /EX, export is\n"
|
|
" saved in ANSI format."
|
|
"/B Show keys in both <root1> and <root2>\n"
|
|
"/C Check internal consistency of memdb.\n"
|
|
"/D Specifies how many levels in the database to enumarate.\n"
|
|
" If 0 (or not specified), all levels are enumarated.\n"
|
|
"/E If <n> is specified, enumerates all entries in fileop.\n"
|
|
" fileop is a numeric value.\n"
|
|
" If <n> is not specified, lists all operation names with vals\n"
|
|
"/ER Specifies root key to export\n"
|
|
"/EF Specifies export output file\n"
|
|
"/F Find keys that have values equal to <value>\n"
|
|
"/FU Find keys that have user flags equal to <value>\n"
|
|
"/FA Find keys that have user flags set to <value>\n"
|
|
"/FO Find keys that have user flags not set to <value>\n"
|
|
"/G MemDbGetValue <key>\n"
|
|
"/H Hide binary dump\n"
|
|
"/I Import an exported file\n"
|
|
"/K Show only keys, not values or user flags.\n"
|
|
"/L List operations for 9x_file\n"
|
|
"/N GetFileStatusOnNt for <value>\n"
|
|
"/NP GetFilePathOnNt for <value>\n"
|
|
"/O If <n> is specified, dumps key at offset <n>\n"
|
|
" If <n> is not specified, displays offset for each key\n"
|
|
"/P Specifies the search pattern for enumaration, and can\n"
|
|
" include a starting path (i.e. HKLM\\*)\n"
|
|
"/S Specifies the starting level (the minimum number of levels\n"
|
|
" before an entry is displayed). Must be less than /D option\n"
|
|
" when a non-zero value is specified for /D. If not specified,\n"
|
|
" all levels are displayed.\n"
|
|
"/V Displays version of ntsetup.dat.\n"
|
|
"/X Show keys in <root1> but not in <root2>\n"
|
|
"/Z Show zero values (default is to show only non-zero values)\n"
|
|
"/$ Dump the hash table\n"
|
|
);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
VOID
|
|
DumpData (
|
|
BYTE const * Data,
|
|
DWORD Count
|
|
);
|
|
|
|
DWORD
|
|
pGetValue (
|
|
IN PCSTR Arg
|
|
)
|
|
{
|
|
INT Base = 10;
|
|
PCSTR p;
|
|
DWORD Value;
|
|
|
|
if (Arg[0] == '0' && tolower (Arg[1]) == 'x') {
|
|
Base = 16;
|
|
} else {
|
|
p = GetEndOfStringA (Arg);
|
|
if (p > Arg) {
|
|
p--;
|
|
if (tolower (*p) == 'h') {
|
|
Base = 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
Value = strtoul (Arg, NULL, Base);
|
|
|
|
return Value;
|
|
}
|
|
|
|
|
|
INT
|
|
__cdecl
|
|
main (
|
|
INT argc,
|
|
CHAR *argv[]
|
|
)
|
|
{
|
|
MEMDB_ENUMA e;
|
|
CHAR *szDepth;
|
|
INT nDepth;
|
|
INT nStartDepth;
|
|
CHAR *szPattern;
|
|
BOOL bNodesOnly = TRUE;
|
|
CHAR *FileSpec;
|
|
INT i;
|
|
INT j;
|
|
MEMDB_VERSION Version;
|
|
DWORD dwReason = DLL_PROCESS_ATTACH;
|
|
BOOL ShowZVals = FALSE;
|
|
BOOL HideDump = FALSE;
|
|
PCSTR NumericalArg;
|
|
BOOL Offset = FALSE;
|
|
DWORD OffsetVal;
|
|
CHAR Key[MEMDB_MAX];
|
|
DWORD RetVal;
|
|
DWORD Flags;
|
|
BOOL GetVal = FALSE;
|
|
PCSTR GetValStr;
|
|
BOOL Check = FALSE;
|
|
PSTR p;
|
|
BOOL KeysOnly = FALSE;
|
|
PSTR DiffRootA = NULL;
|
|
PSTR DiffRootB = NULL;
|
|
BOOL DiffNot = FALSE;
|
|
CHAR RootBuf[MEMDB_MAX * 2];
|
|
CHAR RootPattern[MEMDB_MAX];
|
|
CHAR CompareNode[MEMDB_MAX];
|
|
BOOL Match;
|
|
BOOL DumpHashTable = FALSE;
|
|
BOOL DumpVersion = FALSE;
|
|
HASHENUM HashEnum;
|
|
BOOL FindValue = FALSE;
|
|
DWORD ValueToFind;
|
|
BOOL DisplayOffset = FALSE;
|
|
BOOL UserFlags = FALSE;
|
|
BOOL AndFlags = FALSE;
|
|
BOOL NandFlags = FALSE;
|
|
PCSTR ExportRoot = NULL;
|
|
PCSTR ExportFile = NULL;
|
|
PCSTR File9x = NULL;
|
|
BOOL ListFileOps = FALSE;
|
|
ALL_FILEOPS_ENUM FileOpEnum;
|
|
FILEOP_ENUM eOp;
|
|
FILEOP_PROP_ENUM eOpProp;
|
|
OPERATION LastOperation;
|
|
DWORD EnumOperation = 0;
|
|
PCSTR ImportFile = NULL;
|
|
BOOL AnsiFormat = FALSE;
|
|
PCSTR FileStatusValue = NULL;
|
|
BOOL FilePathWithStatus = FALSE;
|
|
DWORD Status;
|
|
|
|
//
|
|
// Init
|
|
//
|
|
|
|
SuppressAllLogPopups (TRUE);
|
|
|
|
g_hHeap = GetProcessHeap();
|
|
g_hInst = GetModuleHandle(NULL);
|
|
|
|
if (!MigUtil_Entry (g_hInst, dwReason, NULL)) {
|
|
fprintf (stderr, "MigUtil could not init\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MemDb_Entry (g_hInst, dwReason, NULL)) {
|
|
fprintf (stderr, "MemDb could not init\n");
|
|
return FALSE;
|
|
}
|
|
|
|
FileSpec = NULL;
|
|
szPattern = "*";
|
|
nDepth = 0;
|
|
nStartDepth = 0;
|
|
|
|
for (i = 1 ; i < argc ; i++) {
|
|
if (argv[i][0] == '-' || argv[i][0] == '/') {
|
|
switch (tolower (argv[i][1])) {
|
|
|
|
case '?':
|
|
if (argv[i][2] == '?') {
|
|
FullHelpAndExit();
|
|
}
|
|
|
|
HelpAndExit();
|
|
break;
|
|
|
|
case '$':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (DumpHashTable) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
DumpHashTable = TRUE;
|
|
break;
|
|
|
|
case 'i':
|
|
if (ImportFile) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2] == ':') {
|
|
ImportFile = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
ImportFile = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'k':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (KeysOnly) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
KeysOnly = TRUE;
|
|
break;
|
|
|
|
case 'l':
|
|
if (ListFileOps) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
ListFileOps = TRUE;
|
|
|
|
if (argv[i][2] == ':') {
|
|
File9x = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
File9x = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
if (FileStatusValue) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (tolower (argv[i][2]) == 'p') {
|
|
p = &argv[i][3];
|
|
FilePathWithStatus = TRUE;
|
|
} else {
|
|
p = &argv[i][2];
|
|
}
|
|
|
|
if (*p == ':') {
|
|
FileStatusValue = p + 1;
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
FileStatusValue = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
if (DiffRootA) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2] == ':') {
|
|
szPattern = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
szPattern = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
if (argv[i][2] == ':') {
|
|
szDepth = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
szDepth = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
nDepth = pGetValue (szDepth);
|
|
break;
|
|
|
|
case 's':
|
|
if (argv[i][2] == ':') {
|
|
szDepth = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
szDepth = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
nStartDepth = pGetValue (szDepth);
|
|
break;
|
|
|
|
case 'x':
|
|
DiffNot = TRUE;
|
|
|
|
// fall through
|
|
|
|
case 'b':
|
|
if (DiffRootA) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2] != ':') {
|
|
HelpAndExit();
|
|
}
|
|
|
|
StringCopy (RootBuf, &argv[i][3]);
|
|
|
|
DiffRootA = RootBuf;
|
|
DiffRootB = _mbschr (DiffRootA, ',');
|
|
if (!DiffRootB) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
*DiffRootB = 0;
|
|
DiffRootB++;
|
|
while (*DiffRootB == ' ') {
|
|
DiffRootB++;
|
|
}
|
|
|
|
StringCopy (RootPattern, DiffRootA);
|
|
StringCopy (AppendWackA (RootPattern), "*");
|
|
szPattern = RootPattern;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
if (!bNodesOnly) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
bNodesOnly = FALSE;
|
|
break;
|
|
|
|
case 'o':
|
|
if (Offset || DisplayOffset) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2] == ':') {
|
|
OffsetVal = pGetValue (&argv[i][3]);
|
|
Offset = TRUE;
|
|
} else {
|
|
DisplayOffset = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
if (tolower (argv[i][2]) == 'r') {
|
|
if (ExportRoot) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][3] == ':') {
|
|
ExportRoot = &argv[i][4];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
ExportRoot = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (tolower (argv[i][2]) == 'f') {
|
|
if (ExportFile) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][3] == ':') {
|
|
ExportFile = &argv[i][4];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
ExportFile = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (EnumOperation) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (argv[i][2] == ':') {
|
|
|
|
for (j = 0 ; g_PropNames[j].Bit ; j++) {
|
|
if (StringIMatch (&argv[i][3], g_PropNames[j].Name)) {
|
|
EnumOperation = g_PropNames[j].Bit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!g_PropNames[j].Bit) {
|
|
EnumOperation = pGetValue (&argv[i][3]);
|
|
}
|
|
} else {
|
|
printf ("Operations:\n\n");
|
|
|
|
for (j = 0 ; g_PropNames[j].Bit ; j++) {
|
|
printf (" 0x%06X: %s\n", g_PropNames[j].Bit, g_PropNames[j].Name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (!ONEBITSET (EnumOperation)) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
if (FindValue) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
FindValue = TRUE;
|
|
|
|
NumericalArg = &argv[i][2];
|
|
|
|
switch (tolower (*NumericalArg)) {
|
|
|
|
case 'o':
|
|
NandFlags = TRUE;
|
|
NumericalArg++;
|
|
break;
|
|
|
|
case 'a':
|
|
AndFlags = TRUE;
|
|
NumericalArg++;
|
|
break;
|
|
|
|
case 'u':
|
|
UserFlags = TRUE;
|
|
NumericalArg++;
|
|
break;
|
|
}
|
|
|
|
if (*NumericalArg == ':') {
|
|
NumericalArg++;
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
NumericalArg = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
ValueToFind = pGetValue (NumericalArg);
|
|
break;
|
|
|
|
case 'z':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (ShowZVals) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
ShowZVals = TRUE;
|
|
break;
|
|
|
|
case 'h':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (HideDump) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
HideDump = TRUE;
|
|
break;
|
|
|
|
case 'c':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (Check) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
Check = TRUE;
|
|
break;
|
|
|
|
case 'g':
|
|
if (GetVal) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
GetVal = TRUE;
|
|
|
|
if (argv[i][2] == ':') {
|
|
GetValStr = &argv[i][3];
|
|
} else {
|
|
i++;
|
|
if (i < argc) {
|
|
GetValStr = argv[i];
|
|
} else {
|
|
HelpAndExit();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
if (argv[i][2]) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (DumpVersion) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
DumpVersion = TRUE;
|
|
|
|
break;
|
|
|
|
default:
|
|
HelpAndExit();
|
|
}
|
|
} else {
|
|
if (FileSpec) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
FileSpec = argv[i];
|
|
}
|
|
}
|
|
|
|
if (!FileSpec) {
|
|
if (ImportFile) {
|
|
FileSpec = "";
|
|
} else {
|
|
FileSpec = "ntsetup.dat";
|
|
}
|
|
}
|
|
|
|
if (nDepth < nStartDepth)
|
|
HelpAndExit();
|
|
|
|
if (!DumpVersion && !MemDbLoad(FileSpec) && !ImportFile) {
|
|
fprintf(stderr, "MemDbLoad failed. Error: %d\n", GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if (ExportRoot) {
|
|
AnsiFormat = !bNodesOnly;
|
|
}
|
|
|
|
//
|
|
// Validate combinations
|
|
//
|
|
|
|
// Mutually exclusive options, only one can be TRUE:
|
|
if ((
|
|
(EnumOperation != 0) +
|
|
ListFileOps +
|
|
DumpVersion +
|
|
Offset +
|
|
FindValue +
|
|
GetVal +
|
|
DumpHashTable +
|
|
Check +
|
|
(ImportFile != NULL) +
|
|
(ExportRoot != NULL) +
|
|
(FileStatusValue != NULL)
|
|
) > 1) {
|
|
|
|
HelpAndExit();
|
|
}
|
|
|
|
// Strange combinations
|
|
if (DiffRootA && FindValue) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (!ListFileOps && File9x) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if ((ExportRoot && !ExportFile) ||
|
|
(!ExportFile && ExportRoot)
|
|
) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
//
|
|
// memdbt /n (NT file status)
|
|
//
|
|
|
|
if (FileStatusValue) {
|
|
|
|
Status = GetFileStatusOnNt (FileStatusValue);
|
|
|
|
if (Status & FILESTATUS_DELETED) {
|
|
printf ("FILESTATUS_DELETED\n");
|
|
}
|
|
|
|
if (Status & FILESTATUS_MOVED) {
|
|
printf ("FILESTATUS_MOVED\n");
|
|
}
|
|
|
|
if (Status & FILESTATUS_REPLACED) {
|
|
printf ("FILESTATUS_REPLACED\n");
|
|
}
|
|
|
|
if (Status & FILESTATUS_NTINSTALLED) {
|
|
printf ("FILESTATUS_NTINSTALLED\n");
|
|
}
|
|
|
|
if (FilePathWithStatus) {
|
|
p = GetPathStringOnNt (FileStatusValue);
|
|
|
|
if (p) {
|
|
printf ("\nPath: %s\n\n", p);
|
|
FreePathString (p);
|
|
} else {
|
|
printf ("\nPath: <not found>\n\n");
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /i (import)
|
|
//
|
|
|
|
if (ImportFile) {
|
|
|
|
if (!MemDbImport (ImportFile)) {
|
|
fprintf (stderr, "MemDbImport failed for %s. Error: %d\n", ImportFile, GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if (*FileSpec) {
|
|
if (!MemDbSave (FileSpec)) {
|
|
fprintf (stderr, "MemDbSave failed for %s. Error: %d\n", FileSpec, GetLastError());
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /x (export)
|
|
//
|
|
|
|
if (ExportRoot) {
|
|
|
|
if (!MemDbExport (ExportRoot, ExportFile, AnsiFormat)) {
|
|
fprintf (stderr, "MemDbExport failed to export %s to %s. Error: %d\n", ExportRoot, FileSpec, GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /e (enumerate file ops)
|
|
//
|
|
|
|
if (EnumOperation) {
|
|
for (i = 0 ; g_PropNames[i].Bit ; i++) {
|
|
if (g_PropNames[i].Bit & EnumOperation) {
|
|
printf ("Enumeration of %s (0x%06X)\n", g_PropNames[i].Name, g_PropNames[i].Bit);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!g_PropNames[i].Bit) {
|
|
HelpAndExit();
|
|
}
|
|
|
|
if (EnumFirstPathInOperation (&eOp, EnumOperation)) {
|
|
i = 0;
|
|
|
|
do {
|
|
if (i) {
|
|
printf ("\n");
|
|
}
|
|
|
|
i++;
|
|
printf (" %s (seq: %u)\n", eOp.Path, eOp.Sequencer);
|
|
|
|
if (EnumFirstFileOpProperty (&eOpProp, eOp.Sequencer, EnumOperation)) {
|
|
do {
|
|
printf (" %s=%s\n", eOpProp.PropertyName, eOpProp.Property);
|
|
} while (EnumNextFileOpProperty (&eOpProp));
|
|
}
|
|
} while (EnumNextPathInOperation (&eOp));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /l (list file ops)
|
|
//
|
|
|
|
if (ListFileOps) {
|
|
//
|
|
// Enumerate all the properties
|
|
//
|
|
|
|
if (EnumFirstFileOp (&FileOpEnum, ALL_OPERATIONS, File9x)) {
|
|
|
|
CompareNode[0] = 0;
|
|
|
|
do {
|
|
if (!StringMatch (CompareNode, FileOpEnum.Path)) {
|
|
|
|
//
|
|
// Begin processing a new path
|
|
//
|
|
|
|
printf ("\n%s:\n", FileOpEnum.Path);
|
|
StringCopy (CompareNode, FileOpEnum.Path);
|
|
LastOperation = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Print the operation name
|
|
//
|
|
|
|
if (LastOperation != FileOpEnum.CurrentOperation) {
|
|
|
|
LastOperation = FileOpEnum.CurrentOperation;
|
|
|
|
for (i = 0 ; g_PropNames[i].Bit ; i++) {
|
|
if (g_PropNames[i].Bit & FileOpEnum.CurrentOperation) {
|
|
printf (" %s (0x%06X)\n", g_PropNames[i].Name, g_PropNames[i].Bit);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Print the property value
|
|
//
|
|
|
|
if (FileOpEnum.PropertyValid) {
|
|
printf (" %u: %s\n", FileOpEnum.PropertyNum, FileOpEnum.Property);
|
|
}
|
|
|
|
} while (EnumNextFileOp (&FileOpEnum));
|
|
|
|
} else {
|
|
printf ("%s:\n\n No operations.", File9x);
|
|
}
|
|
|
|
printf ("\n");
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /v (dump version)
|
|
//
|
|
|
|
if (DumpVersion) {
|
|
|
|
if (MemDbQueryVersion (FileSpec, &Version)) {
|
|
printf (
|
|
"Version: %u %s\n"
|
|
"Type: %s\n",
|
|
Version.Version,
|
|
Version.CurrentVersion ? "(same as memdbt)" : "(not the same as memdbt)",
|
|
Version.Debug ? "Checked Build" : "Free Build"
|
|
);
|
|
|
|
} else {
|
|
fprintf (stderr, "%s is not a valid memdb file\n", FileSpec);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /o:<offset> usage. (Get Key by offset)
|
|
//
|
|
if (Offset) {
|
|
if (!MemDbBuildKeyFromOffset (OffsetVal, Key, 0, &RetVal)) {
|
|
fprintf(stderr, "No key at specified offset.\n");
|
|
} else {
|
|
printf("%s", Key);
|
|
if (RetVal || ShowZVals) {
|
|
printf (" = %u (0x%X)", RetVal, RetVal);
|
|
}
|
|
|
|
printf ("\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /g:<key> usage. (Get value of key)
|
|
//
|
|
if (GetVal) {
|
|
if (!MemDbGetValue (GetValStr, &RetVal)) {
|
|
fprintf (stderr, "%s does not exist", GetValStr);
|
|
} else {
|
|
printf ("Value of %s: %u\n", GetValStr, RetVal);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /$ usage. (Dump hash table)
|
|
//
|
|
if (DumpHashTable) {
|
|
if (EnumFirstHashEntry (&HashEnum)) {
|
|
do {
|
|
if (!MemDbBuildKeyFromOffset (HashEnum.BucketPtr->Offset, Key, 0, &RetVal)) {
|
|
fprintf(stderr, "No key at offset %u.\n", HashEnum.BucketPtr->Offset);
|
|
} else {
|
|
printf("%s", Key);
|
|
if (RetVal || ShowZVals) {
|
|
printf (" = %u (0x%X)", RetVal, RetVal);
|
|
}
|
|
|
|
printf ("\n");
|
|
}
|
|
|
|
} while (EnumNextHashEntry (&HashEnum));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// memdbt /c usage. (Check consistency)
|
|
//
|
|
if (Check) {
|
|
if (MemDbEnumFirstValue(&e, szPattern, 0, MEMDB_ENDPOINTS_ONLY)) {
|
|
|
|
BOOL NoProblems = TRUE;
|
|
|
|
do {
|
|
|
|
if (!MemDbGetValueAndFlags(e.szName, &RetVal, &Flags)) {
|
|
fprintf(stderr, "Error - MemDbGetValueAndFlags failed for %s.\n",e.szName);
|
|
NoProblems = FALSE;
|
|
}
|
|
|
|
|
|
} while (MemDbEnumNextValue(&e));
|
|
|
|
if (NoProblems) {
|
|
fprintf(stderr, "Memdb consistency check completed. No problems detected.\n");
|
|
}
|
|
else {
|
|
fprintf(stderr, "One or more problems were found during the memdb consistency check.\n");
|
|
}
|
|
|
|
}
|
|
else {
|
|
fprintf(stderr, "Memdb empty. Nothing to check.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// normal usage and comparison option
|
|
//
|
|
if (MemDbEnumFirstValue (
|
|
&e,
|
|
szPattern,
|
|
nDepth,
|
|
bNodesOnly ? MEMDB_ENDPOINTS_ONLY : NO_FLAGS
|
|
)) {
|
|
|
|
do {
|
|
//
|
|
// Comparison option
|
|
//
|
|
|
|
if (DiffRootA) {
|
|
//
|
|
// Do a MemDbGetValue
|
|
//
|
|
|
|
StringCopy (CompareNode, DiffRootB);
|
|
StringCopy (AppendWack (CompareNode), e.szName);
|
|
|
|
Match = MemDbGetValue (CompareNode, NULL);
|
|
|
|
//
|
|
// Skip if (A) DiffNot is FALSE and no match
|
|
// (B) DiffNot is TRUE and match
|
|
//
|
|
|
|
if (Match == DiffNot) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Normal usage/find value
|
|
//
|
|
|
|
if (e.PosCount >= nStartDepth) {
|
|
//
|
|
// Find value option
|
|
//
|
|
|
|
if (FindValue) {
|
|
if (UserFlags) {
|
|
if (e.UserFlags != ValueToFind) {
|
|
continue;
|
|
}
|
|
} else if (AndFlags) {
|
|
if ((e.UserFlags & ValueToFind) == 0) {
|
|
continue;
|
|
}
|
|
} else if (NandFlags) {
|
|
if (e.UserFlags & ValueToFind) {
|
|
continue;
|
|
}
|
|
} else if (e.dwValue != ValueToFind) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Key output
|
|
//
|
|
|
|
if (DisplayOffset) {
|
|
printf ("[%08X] ", e.Offset);
|
|
}
|
|
|
|
if (e.bBinary && !KeysOnly) {
|
|
if (!HideDump) {
|
|
printf ("%s: (%u byte%s)\n", e.szName, e.BinarySize, e.BinarySize == 1 ? "" : "s");
|
|
DumpData (e.BinaryPtr, e.BinarySize);
|
|
printf ("\n");
|
|
} else {
|
|
printf ("%s (%u byte%s)\n", e.szName, e.BinarySize, e.BinarySize == 1 ? "" : "s");
|
|
}
|
|
} else {
|
|
if (!KeysOnly) {
|
|
if (e.dwValue || ShowZVals) {
|
|
printf("%s = 0x%02lX", e.szName, e.dwValue);
|
|
} else {
|
|
printf("%s", e.szName);
|
|
}
|
|
|
|
if (e.UserFlags || ShowZVals) {
|
|
printf(", Flags: %04x", e.UserFlags);
|
|
}
|
|
} else {
|
|
printf("%s", e.szName);
|
|
}
|
|
|
|
printf ("\n");
|
|
}
|
|
}
|
|
} while (MemDbEnumNextValue(&e));
|
|
}
|
|
|
|
dwReason = DLL_PROCESS_DETACH;
|
|
MemDb_Entry (g_hInst, dwReason, NULL);
|
|
MigUtil_Entry (g_hInst, dwReason, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpData (
|
|
IN BYTE const * Data,
|
|
IN DWORD Count
|
|
)
|
|
{
|
|
DWORD i, j, k;
|
|
|
|
for (i = 0 ; i < Count ; i = k) {
|
|
printf (" %08X ", i);
|
|
k = i + 16;
|
|
for (j = i ; j < k && j < Count ; j++) {
|
|
printf ("%02X ", Data[j]);
|
|
}
|
|
|
|
while (j < k) {
|
|
printf (" ");
|
|
j++;
|
|
}
|
|
|
|
for (j = i ; j < k && j < Count ; j++) {
|
|
if (isprint (Data[j])) {
|
|
printf ("%c", Data[j]);
|
|
} else {
|
|
printf (".");
|
|
}
|
|
}
|
|
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
|