diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt index 8cd59fcbd..6cf972699 100644 --- a/2.x/trunk/CHANGELOG.txt +++ b/2.x/trunk/CHANGELOG.txt @@ -9,6 +9,7 @@ Process Hacker * Relative start times * FIXED: * Run and Run As shortcuts + * Command line handling 2.1 * NEW/IMPROVED: diff --git a/2.x/trunk/ProcessHacker/main.c b/2.x/trunk/ProcessHacker/main.c index 69fa0be60..5caa3b608 100644 --- a/2.x/trunk/ProcessHacker/main.c +++ b/2.x/trunk/ProcessHacker/main.c @@ -597,22 +597,19 @@ BOOLEAN NTAPI PhpCommandLineOptionCallback( } else { - if (Value) + PPH_STRING lowerValue; + + lowerValue = PhDuplicateString(Value); + PhLowerString(lowerValue); + + if (PhStringIndexOfString(lowerValue, 0, L"taskmgr.exe") != -1) { - PPH_STRING lowerValue; - - lowerValue = PhDuplicateString(Value); - PhLowerString(lowerValue); - - if (PhStringIndexOfString(lowerValue, 0, L"taskmgr.exe") != -1) - { - // User probably has Process Hacker replacing Task Manager. Force - // the main window to start visible. - PhStartupParameters.ShowVisible = TRUE; - } - - PhDereferenceObject(lowerValue); + // User probably has Process Hacker replacing Task Manager. Force + // the main window to start visible. + PhStartupParameters.ShowVisible = TRUE; } + + PhDereferenceObject(lowerValue); } return TRUE; @@ -649,7 +646,7 @@ VOID PhpProcessStartupParameters() &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART | PH_COMMAND_LINE_CALLBACK_ALL_MAIN, + PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS | PH_COMMAND_LINE_IGNORE_FIRST_PART, PhpCommandLineOptionCallback, NULL )) diff --git a/2.x/trunk/ProcessHacker/runas.c b/2.x/trunk/ProcessHacker/runas.c index 0a26d2753..a184dffcf 100644 --- a/2.x/trunk/ProcessHacker/runas.c +++ b/2.x/trunk/ProcessHacker/runas.c @@ -635,6 +635,8 @@ VOID PhSetDesktopWinStaAccess() HDESK desktopHandle; SECURITY_DESCRIPTOR securityDescriptor; + // TODO: Set security on the correct window station and desktop. + // Create a security descriptor with a NULL DACL, // thereby allowing everyone to access the object. RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION); @@ -661,53 +663,6 @@ VOID PhSetDesktopWinStaAccess() } } -/** - * Escapes a string C-style for use in a command line. - * - * \param String The string to escape. - * - * \return The escaped string. - * - * \remarks Only backslash (\\) and quote characters (", ') are - * escaped. - */ -PPH_STRING PhpCEscapeString( - __in PPH_STRINGREF String - ) -{ - PPH_STRING string; - PH_STRING_BUILDER stringBuilder; - ULONG length; - ULONG i; - WCHAR temp[2]; - - length = String->Length / 2; - PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); - - temp[0] = '\\'; - - for (i = 0; i < length; i++) - { - switch (String->Buffer[i]) - { - case '\\': - case '\"': - case '\'': - temp[1] = String->Buffer[i]; - PhStringBuilderAppendEx(&stringBuilder, temp, 4); - break; - default: - PhStringBuilderAppendChar(&stringBuilder, String->Buffer[i]); - break; - } - } - - string = PhReferenceStringBuilderString(&stringBuilder); - PhDeleteStringBuilder(&stringBuilder); - - return string; -} - PPH_STRING PhpBuildRunAsServiceCommandLine( __in PWSTR Program, __in_opt PWSTR UserName, @@ -734,14 +689,14 @@ PPH_STRING PhpBuildRunAsServiceCommandLine( PhStringBuilderAppend2(&commandLineBuilder, L"\" -ras"); PhInitializeStringRef(&stringRef, Program); - string = PhpCEscapeString(&stringRef); + string = PhEscapeCommandLinePart(&stringRef); PhStringBuilderAppend2(&commandLineBuilder, L" -c \""); PhStringBuilderAppend(&commandLineBuilder, string); PhStringBuilderAppendChar(&commandLineBuilder, '\"'); PhDereferenceObject(string); PhInitializeStringRef(&stringRef, DesktopName); - string = PhpCEscapeString(&stringRef); + string = PhEscapeCommandLinePart(&stringRef); PhStringBuilderAppend2(&commandLineBuilder, L" -D \""); PhStringBuilderAppend(&commandLineBuilder, string); PhStringBuilderAppendChar(&commandLineBuilder, '\"'); @@ -750,14 +705,14 @@ PPH_STRING PhpBuildRunAsServiceCommandLine( if (!ProcessIdWithToken) { PhInitializeStringRef(&stringRef, UserName); - string = PhpCEscapeString(&stringRef); + string = PhEscapeCommandLinePart(&stringRef); PhStringBuilderAppend2(&commandLineBuilder, L" -u \""); PhStringBuilderAppend(&commandLineBuilder, string); PhStringBuilderAppendChar(&commandLineBuilder, '\"'); PhDereferenceObject(string); PhInitializeStringRef(&stringRef, Password); - string = PhpCEscapeString(&stringRef); + string = PhEscapeCommandLinePart(&stringRef); PhStringBuilderAppend2(&commandLineBuilder, L" -p \""); PhStringBuilderAppend(&commandLineBuilder, string); PhStringBuilderAppendChar(&commandLineBuilder, '\"'); @@ -979,7 +934,7 @@ NTSTATUS PhRunAsCommandStart2( L"-c -ctype processhacker -caction runas -cobject \"" ); - string = PhpCEscapeString(&commandLine->sr); + string = PhEscapeCommandLinePart(&commandLine->sr); PhStringBuilderAppend(&argumentsBuilder, string); PhDereferenceObject(string); diff --git a/2.x/trunk/lib/lib32/ntdll.exp b/2.x/trunk/lib/lib32/ntdll.exp index 06e22c068..6ca67b81f 100644 Binary files a/2.x/trunk/lib/lib32/ntdll.exp and b/2.x/trunk/lib/lib32/ntdll.exp differ diff --git a/2.x/trunk/lib/lib32/ntdll.lib b/2.x/trunk/lib/lib32/ntdll.lib index 7d84a1f5d..978d315a4 100644 Binary files a/2.x/trunk/lib/lib32/ntdll.lib and b/2.x/trunk/lib/lib32/ntdll.lib differ diff --git a/2.x/trunk/lib/lib32/samlib.exp b/2.x/trunk/lib/lib32/samlib.exp index df3a17a53..1e628c666 100644 Binary files a/2.x/trunk/lib/lib32/samlib.exp and b/2.x/trunk/lib/lib32/samlib.exp differ diff --git a/2.x/trunk/lib/lib32/samlib.lib b/2.x/trunk/lib/lib32/samlib.lib index ac8cb9b94..c6040532f 100644 Binary files a/2.x/trunk/lib/lib32/samlib.lib and b/2.x/trunk/lib/lib32/samlib.lib differ diff --git a/2.x/trunk/lib/lib64/ntdll.exp b/2.x/trunk/lib/lib64/ntdll.exp index 915b09315..68d86f114 100644 Binary files a/2.x/trunk/lib/lib64/ntdll.exp and b/2.x/trunk/lib/lib64/ntdll.exp differ diff --git a/2.x/trunk/lib/lib64/ntdll.lib b/2.x/trunk/lib/lib64/ntdll.lib index 0cae5e1a6..0aa5425a5 100644 Binary files a/2.x/trunk/lib/lib64/ntdll.lib and b/2.x/trunk/lib/lib64/ntdll.lib differ diff --git a/2.x/trunk/lib/lib64/samlib.exp b/2.x/trunk/lib/lib64/samlib.exp index e6698fe00..7f2ac4a29 100644 Binary files a/2.x/trunk/lib/lib64/samlib.exp and b/2.x/trunk/lib/lib64/samlib.exp differ diff --git a/2.x/trunk/lib/lib64/samlib.lib b/2.x/trunk/lib/lib64/samlib.lib index bfd2b5a7c..95401848f 100644 Binary files a/2.x/trunk/lib/lib64/samlib.lib and b/2.x/trunk/lib/lib64/samlib.lib differ diff --git a/2.x/trunk/phlib/basesup.c b/2.x/trunk/phlib/basesup.c index 312be9c54..90c803fcc 100644 --- a/2.x/trunk/phlib/basesup.c +++ b/2.x/trunk/phlib/basesup.c @@ -1364,12 +1364,13 @@ VOID PhFullStringAppend2( * Appends a string to the end of a string. * * \param String A string object. - * \param Buffer The string to append. + * \param Buffer The string to append. Specify NULL + * to simply reserve \a Length bytes. * \param Length The number of bytes to append. */ VOID PhFullStringAppendEx( __inout PPH_FULL_STRING String, - __in PWSTR Buffer, + __in_opt PWSTR Buffer, __in SIZE_T Length ) { @@ -1380,11 +1381,15 @@ VOID PhFullStringAppendEx( if (String->AllocatedLength < String->Length + Length) PhResizeFullString(String, String->Length + Length, TRUE); - memcpy( - &String->Buffer[String->Length / sizeof(WCHAR)], - Buffer, - Length - ); + if (Buffer) + { + memcpy( + &String->Buffer[String->Length / sizeof(WCHAR)], + Buffer, + Length + ); + } + String->Length += Length; PhpWriteFullStringNullTerminator(String); } @@ -1408,6 +1413,35 @@ VOID PhFullStringAppendChar( PhpWriteFullStringNullTerminator(String); } +/** + * Appends a number of characters to the end of a string. + * + * \param String A string object. + * \param Character The character to append. + * \param Count The number of times to append the character. + */ +VOID PhFullStringAppendChar2( + __inout PPH_FULL_STRING String, + __in WCHAR Character, + __in SIZE_T Count + ) +{ + if (Count == 0) + return; + + if (String->AllocatedLength < String->Length + Count * sizeof(WCHAR)) + PhResizeFullString(String, String->Length + Count * sizeof(WCHAR), TRUE); + + wmemset( + &String->Buffer[String->Length / sizeof(WCHAR)], + Character, + Count + ); + + String->Length += Count * sizeof(WCHAR); + PhpWriteFullStringNullTerminator(String); +} + /** * Appends a formatted string to the end of a string. * @@ -1603,12 +1637,13 @@ VOID PhStringBuilderAppend2( * string. * * \param StringBuilder A string builder object. - * \param String The string to append. + * \param String The string to append. Specify NULL to + * simply reserve \a Length bytes. * \param Length The number of bytes to append. */ VOID PhStringBuilderAppendEx( __inout PPH_STRING_BUILDER StringBuilder, - __in PWSTR String, + __in_opt PWSTR String, __in ULONG Length ) { @@ -1623,11 +1658,15 @@ VOID PhStringBuilderAppendEx( // Copy the string, add the length, then write the null terminator. - memcpy( - &StringBuilder->String->Buffer[StringBuilder->String->Length / sizeof(WCHAR)], - String, - Length - ); + if (String) + { + memcpy( + &StringBuilder->String->Buffer[StringBuilder->String->Length / sizeof(WCHAR)], + String, + Length + ); + } + StringBuilder->String->Length += (USHORT)Length; PhpWriteStringBuilderNullTerminator(StringBuilder); } @@ -1654,6 +1693,39 @@ VOID PhStringBuilderAppendChar( PhpWriteStringBuilderNullTerminator(StringBuilder); } +/** + * Appends a number of characters to the end of a string + * builder string. + * + * \param StringBuilder A string builder object. + * \param Character The character to append. + * \param Count The number of times to append the character. + */ +VOID PhStringBuilderAppendChar2( + __inout PPH_STRING_BUILDER StringBuilder, + __in WCHAR Character, + __in ULONG Count + ) +{ + if (Count == 0) + return; + + // See if we need to re-allocate the string. + if (StringBuilder->AllocatedLength < StringBuilder->String->Length + Count * sizeof(WCHAR)) + { + PhpResizeStringBuilder(StringBuilder, StringBuilder->String->Length + Count * sizeof(WCHAR)); + } + + wmemset( + &StringBuilder->String->Buffer[StringBuilder->String->Length / sizeof(WCHAR)], + Character, + Count + ); + + StringBuilder->String->Length += (USHORT)(Count * sizeof(WCHAR)); + PhpWriteStringBuilderNullTerminator(StringBuilder); +} + /** * Appends a formatted string to the end of a string builder * string. @@ -1726,13 +1798,14 @@ VOID PhStringBuilderInsert2( * \param StringBuilder A string builder object. * \param Index The index, in characters, at which to * insert the string. - * \param String The string to insert. + * \param String The string to insert. Specify NULL to + * simply reserve \a Length bytes. * \param Length The number of bytes to insert. */ VOID PhStringBuilderInsertEx( __inout PPH_STRING_BUILDER StringBuilder, __in ULONG Index, - __in PWSTR String, + __in_opt PWSTR String, __in ULONG Length ) { @@ -1755,12 +1828,15 @@ VOID PhStringBuilderInsertEx( ); } - // Copy the new string. - memcpy( - &StringBuilder->String->Buffer[Index], - String, - Length - ); + if (String) + { + // Copy the new string. + memcpy( + &StringBuilder->String->Buffer[Index], + String, + Length + ); + } StringBuilder->String->Length += (USHORT)Length; PhpWriteStringBuilderNullTerminator(StringBuilder); diff --git a/2.x/trunk/phlib/include/ph.h b/2.x/trunk/phlib/include/ph.h index ef8b759ab..e5dacbd0f 100644 --- a/2.x/trunk/phlib/include/ph.h +++ b/2.x/trunk/phlib/include/ph.h @@ -2532,7 +2532,6 @@ typedef BOOLEAN (NTAPI *PPH_COMMAND_LINE_CALLBACK)( #define PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS 0x1 #define PH_COMMAND_LINE_IGNORE_FIRST_PART 0x2 -#define PH_COMMAND_LINE_CALLBACK_ALL_MAIN 0x4 PHLIBAPI PPH_STRING PhParseCommandLinePart( @@ -2543,11 +2542,16 @@ PPH_STRING PhParseCommandLinePart( PHLIBAPI BOOLEAN PhParseCommandLine( __in PPH_STRINGREF CommandLine, - __in PPH_COMMAND_LINE_OPTION Options, + __in_opt PPH_COMMAND_LINE_OPTION Options, __in ULONG NumberOfOptions, __in ULONG Flags, __in PPH_COMMAND_LINE_CALLBACK Callback, __in PVOID Context ); +PHLIBAPI +PPH_STRING PhEscapeCommandLinePart( + __in PPH_STRINGREF String + ); + #endif diff --git a/2.x/trunk/phlib/include/phbase.h b/2.x/trunk/phlib/include/phbase.h index acb35556e..ab8614fcd 100644 --- a/2.x/trunk/phlib/include/phbase.h +++ b/2.x/trunk/phlib/include/phbase.h @@ -1539,7 +1539,7 @@ VOID NTAPI PhFullStringAppendEx( __inout PPH_FULL_STRING String, - __in PWSTR Buffer, + __in_opt PWSTR Buffer, __in SIZE_T Length ); @@ -1551,6 +1551,15 @@ PhFullStringAppendChar( __in WCHAR Character ); +PHLIBAPI +VOID +NTAPI +PhFullStringAppendChar2( + __inout PPH_FULL_STRING String, + __in WCHAR Character, + __in SIZE_T Count + ); + PHLIBAPI VOID NTAPI @@ -1633,7 +1642,7 @@ VOID NTAPI PhStringBuilderAppendEx( __inout PPH_STRING_BUILDER StringBuilder, - __in PWSTR String, + __in_opt PWSTR String, __in ULONG Length ); @@ -1645,6 +1654,15 @@ PhStringBuilderAppendChar( __in WCHAR Character ); +PHLIBAPI +VOID +NTAPI +PhStringBuilderAppendChar2( + __inout PPH_STRING_BUILDER StringBuilder, + __in WCHAR Character, + __in ULONG Count + ); + PHLIBAPI VOID NTAPI @@ -1678,7 +1696,7 @@ NTAPI PhStringBuilderInsertEx( __inout PPH_STRING_BUILDER StringBuilder, __in ULONG Index, - __in PWSTR String, + __in_opt PWSTR String, __in ULONG Length ); diff --git a/2.x/trunk/phlib/support.c b/2.x/trunk/phlib/support.c index db6c87cad..9f1aafd5d 100644 --- a/2.x/trunk/phlib/support.c +++ b/2.x/trunk/phlib/support.c @@ -2996,69 +2996,79 @@ PPH_STRING PhParseCommandLinePart( ULONG length; ULONG i; - BOOLEAN inEscape; + ULONG numberOfBackslashes; BOOLEAN inQuote; BOOLEAN endOfValue; length = CommandLine->Length / 2; i = *Index; + // This function follows the rules used by CommandLineToArgvW: + // + // * 2n backslashes and a quotation mark produces n backslashes and a quotation mark (non-literal). + // * 2n + 1 backslashes and a quotation mark produces n and a quotation mark (literal). + // * n backslashes and no quotation mark produces n backslashes. + PhInitializeStringBuilder(&stringBuilder, 10); - inEscape = FALSE; + numberOfBackslashes = 0; inQuote = FALSE; endOfValue = FALSE; for (; i < length; i++) { - if (inEscape) + switch (CommandLine->Buffer[i]) { - switch (CommandLine->Buffer[i]) + case '\\': + numberOfBackslashes++; + break; + case '\"': + if (numberOfBackslashes != 0) + { + if (numberOfBackslashes & 1) + { + numberOfBackslashes /= 2; + + if (numberOfBackslashes != 0) + { + PhStringBuilderAppendChar2(&stringBuilder, '\\', numberOfBackslashes); + numberOfBackslashes = 0; + } + + PhStringBuilderAppendChar(&stringBuilder, '\"'); + + break; + } + else + { + numberOfBackslashes /= 2; + PhStringBuilderAppendChar2(&stringBuilder, '\\', numberOfBackslashes); + numberOfBackslashes = 0; + } + } + + if (!inQuote) + inQuote = TRUE; + else + inQuote = FALSE; + + break; + default: + if (numberOfBackslashes != 0) + { + PhStringBuilderAppendChar2(&stringBuilder, '\\', numberOfBackslashes); + numberOfBackslashes = 0; + } + + if (CommandLine->Buffer[i] == ' ' && !inQuote) + { + endOfValue = TRUE; + } + else { - case '\\': - case '\"': - case '\'': PhStringBuilderAppendChar(&stringBuilder, CommandLine->Buffer[i]); - break; - default: - // Unknown escape. Append both the backslash and - // escape character. - PhStringBuilderAppendEx( - &stringBuilder, - &CommandLine->Buffer[i - 1], - 4 - ); - break; } - inEscape = FALSE; - } - else - { - switch (CommandLine->Buffer[i]) - { - case '\\': - inEscape = TRUE; - break; - case '\"': - case '\'': - if (!inQuote) - inQuote = TRUE; - else - inQuote = FALSE; - - break; - default: - if (CommandLine->Buffer[i] == ' ' && !inQuote) - { - endOfValue = TRUE; - } - else - { - PhStringBuilderAppendChar(&stringBuilder, CommandLine->Buffer[i]); - } - - break; - } + break; } if (endOfValue) @@ -3075,7 +3085,7 @@ PPH_STRING PhParseCommandLinePart( BOOLEAN PhParseCommandLine( __in PPH_STRINGREF CommandLine, - __in PPH_COMMAND_LINE_OPTION Options, + __in_opt PPH_COMMAND_LINE_OPTION Options, __in ULONG NumberOfOptions, __in ULONG Flags, __in PPH_COMMAND_LINE_CALLBACK Callback, @@ -3092,8 +3102,6 @@ BOOLEAN PhParseCommandLine( PPH_COMMAND_LINE_OPTION option = NULL; PPH_STRING optionValue; - PPH_STRING mainArgumentValue = NULL; - if (CommandLine->Length == 0) return TRUE; @@ -3178,51 +3186,93 @@ BOOLEAN PhParseCommandLine( } else { - // If PH_COMMAND_LINE_CALLBACK_ALL_MAIN was not specified: - // Value with no option. This becomes our "main argument". - // If we had a previous "main argument", replace it with - // this one. + PPH_STRING value; - if (mainArgumentValue) - PhDereferenceObject(mainArgumentValue); - - mainArgumentValue = PhParseCommandLinePart(CommandLine, &i); + value = PhParseCommandLinePart(CommandLine, &i); if ((Flags & PH_COMMAND_LINE_IGNORE_FIRST_PART) && wasFirst) { - if (mainArgumentValue) - { - PhDereferenceObject(mainArgumentValue); - mainArgumentValue = NULL; - } + PhDereferenceObject(value); + value = NULL; } - if (Flags & PH_COMMAND_LINE_CALLBACK_ALL_MAIN) + if (value) { - // This makes PH_COMMAND_LINE_CALLBACK_ALL_MAIN cooperate with - // PH_COMMAND_LINE_IGNORE_FIRST_PART. - if (mainArgumentValue) - { - cont = Callback(NULL, mainArgumentValue, Context); - PhDereferenceObject(mainArgumentValue); - mainArgumentValue = NULL; + cont = Callback(NULL, value, Context); + PhDereferenceObject(value); - if (!cont) - break; - } + if (!cont) + break; } wasFirst = FALSE; } } - // If PH_COMMAND_LINE_CALLBACK_ALL_MAIN is enabled this won't run - // because mainArgumentValue is set to NULL after processing. - if (mainArgumentValue) - { - Callback(NULL, mainArgumentValue, Context); - PhDereferenceObject(mainArgumentValue); - } - return TRUE; } + +/** + * Escapes a string for use in a command line. + * + * \param String The string to escape. + * + * \return The escaped string. + * + * \remarks Only the double quotation mark is escaped. + */ +PPH_STRING PhEscapeCommandLinePart( + __in PPH_STRINGREF String + ) +{ + static WCHAR backslashAndQuote[2] = { '\\', '\"' }; + + PPH_STRING string; + PH_STRING_BUILDER stringBuilder; + ULONG length; + ULONG i; + + ULONG numberOfBackslashes; + + length = String->Length / 2; + PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3); + numberOfBackslashes = 0; + + // Simply replacing " with \" won't work here. See PhParseCommandLinePart + // for the quoting rules. + + for (i = 0; i < length; i++) + { + switch (String->Buffer[i]) + { + case '\\': + numberOfBackslashes++; + break; + case '\"': + if (numberOfBackslashes != 0) + { + PhStringBuilderAppendChar2(&stringBuilder, '\\', numberOfBackslashes * 2); + numberOfBackslashes = 0; + } + + PhStringBuilderAppendEx(&stringBuilder, backslashAndQuote, sizeof(backslashAndQuote)); + + break; + default: + if (numberOfBackslashes != 0) + { + PhStringBuilderAppendChar2(&stringBuilder, '\\', numberOfBackslashes); + numberOfBackslashes = 0; + } + + PhStringBuilderAppendChar(&stringBuilder, String->Buffer[i]); + + break; + } + } + + string = PhReferenceStringBuilderString(&stringBuilder); + PhDeleteStringBuilder(&stringBuilder); + + return string; +} diff --git a/2.x/trunk/tools/fiin/main.c b/2.x/trunk/tools/fiin/main.c index 88c3cd161..6a9170d50 100644 --- a/2.x/trunk/tools/fiin/main.c +++ b/2.x/trunk/tools/fiin/main.c @@ -294,7 +294,7 @@ int __cdecl main(int argc, char *argv[]) &commandLine, options, sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION), - PH_COMMAND_LINE_IGNORE_FIRST_PART | PH_COMMAND_LINE_CALLBACK_ALL_MAIN, + PH_COMMAND_LINE_IGNORE_FIRST_PART, FiCommandLineCallback, NULL ) || FiArgHelp) diff --git a/2.x/trunk/tools/fixlib/bin/Release/fixlib.exe b/2.x/trunk/tools/fixlib/bin/Release/fixlib.exe index 688bbf5bf..d89daad93 100644 Binary files a/2.x/trunk/tools/fixlib/bin/Release/fixlib.exe and b/2.x/trunk/tools/fixlib/bin/Release/fixlib.exe differ