Debugging A PowerShell String

A friend had asked for some assistance with a script that was adding objects into Active Directory. It was failing to create Active Directory groups – “Invalid DN Syntax” was the descriptive message we received.

However the DN syntax appeared to be valid:

image

And when we copied and pasted the text from $groupname it worked fine…

image

So what was the difference?

To find if the strings were different we did a compare:

image

OK, trimmed they match. But when we surrounded $groupname with exclamation points there weren’t any spaces or tabs…

To find out why we check the string at byte level. To do this we used:

[System.Text.Encoding]::Unicode.GetBytes($groupname)

Broken Working

77
0
121
0
65
0
68
0
71
0
114
0
111
0
117
0
112
0
13
0

77
0
121
0
65
0
68
0
71
0
114
0
111
0
117
0
112
0

We can see the broken one has a carriage return at the end ( In PowerShell “`r” )

The problem was a file had been retrieved split by line feed ( In PowerShell “`n”) But Windows text files usually end in Carriage Return + Line Feed (“`r`n”) It is the line feed that moves text onto the next line, so that is why we didn’t see any spaces when printing string in PowerShell. PowerShell just doesn’t display the unprintable characters.

In the days of VBScript I found similar issues with tabs in the text file. In the case of VBScript the Trim function doesn’t remove these.

Posted in PowerShell, Debugging | Tagged | Leave a comment

When Windows 8.1 VM Host Runs Out of Disk Space…

When copying a large file in Windows 8.1 Parallels Virtual Machine, the host ran out of disk space…

image

We can see from the stack trace explorer was copying file at time of crash…

0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

IRQL_NOT_LESS_OR_EQUAL (a)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high.  This is usually
caused by drivers using improper addresses.
If a kernel debugger is available get the stack backtrace.
Arguments:
Arg1: 0000000000000000, memory referenced
Arg2: 0000000000000002, IRQLw
Arg3: 0000000000000000, bitfield :
    bit 0 : value 0 = read operation, 1 = write operation
    bit 3 : value 0 = not an execute operation, 1 = execute operation (only on chips which support this level of status)
Arg4: fffff8007689692a, address which referenced memory

Debugging Details:
——————

READ_ADDRESS: unable to get nt!MmNonPagedPoolStart
unable to get nt!MmSizeOfNonPagedPoolInBytes
0000000000000000

CURRENT_IRQL:  2

FAULTING_IP:
nt!MiAddViewsForSection+22
fffff800`7689692a 488b01          mov     rax,qword ptr [rcx]

DEFAULT_BUCKET_ID:  WIN8_DRIVER_FAULT

BUGCHECK_STR:  AV

PROCESS_NAME:  explorer.exe

ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) amd64fre

TRAP_FRAME:  ffffd00021a6cd90 — (.trap 0xffffd00021a6cd90)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=ffffd00021a6cf88 rbx=0000000000000000 rcx=0000000000000000
rdx=000000000005b500 rsi=0000000000000000 rdi=0000000000000000
rip=fffff8007689692a rsp=ffffd00021a6cf20 rbp=ffffe001f0f943d0
r8=fffff6d80022b000  r9=ffffd00021a6cfd0 r10=fffff6c000000000
r11=ffffd00021a6cf60 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz na pe nc
nt!MiAddViewsForSection+0x22:
fffff800`7689692a 488b01          mov     rax,qword ptr [rcx] ds:00000000`00000000=????????????????
Resetting default scope

LAST_CONTROL_TRANSFER:  from fffff8007697dae9 to fffff80076971fa0

STACK_TEXT: 
ffffd000`21a6cc48 fffff800`7697dae9 : 00000000`0000000a 00000000`00000000 00000000`00000002 00000000`00000000 : nt!KeBugCheckEx
ffffd000`21a6cc50 fffff800`7697c33a : 00000000`00000000 00000000`00000000 fffff800`76b6b000 ffffd000`21a6cd90 : nt!KiBugCheckDispatch+0x69
ffffd000`21a6cd90 fffff800`7689692a : 00000000`00000200 00000000`00000004 00000000`0000002f ffffe001`f08a8770 : nt!KiPageFault+0x23a
ffffd000`21a6cf20 fffff800`768aff8f : 00000000`00000000 00000000`0005b500 00000000`00000000 ffffd000`21a6cfd0 : nt!MiAddViewsForSection+0x22
ffffd000`21a6cf90 fffff800`768ae0d7 : fffff800`7681e000 00000000`00000001 00000000`00000001 fffff800`76b04830 : nt!MmMapViewInSystemCache+0x113
ffffd000`21a6d100 fffff800`7689f6ff : 00000000`00000001 ffffe001`eeae2010 00000000`00000000 00000000`00000000 : nt!CcGetVacbMiss+0xef
ffffd000`21a6d190 fffff800`7689bd13 : 00000000`00000000 00000000`5b500000 ffffd000`21a6d298 ffffd000`21a6d26c : nt!CcGetVirtualAddress+0x36f
ffffd000`21a6d230 fffff800`7689b313 : ffffe001`eeae2010 00000000`37782040 ffffd000`21a6d388 00000000`00100000 : nt!CcMapAndCopyInToCache+0x157
ffffd000`21a6d320 fffff800`769e07e9 : ffffe001`f14705c0 ffffe001`f14705c0 00000000`5b500000 00000000`5b500000 : nt!CcCopyWriteEx+0x1bb
ffffd000`21a6d3c0 fffff800`8922d393 : ffffc000`805b3480 ffffe001`f14705c0 fffff800`89230500 00000000`5b500000 : nt!CcCopyWrite+0x19
ffffd000`21a6d400 fffff800`8920a841 : ffffe001`f148ea80 ffffe001`f14705c0 ffffe001`ef2ec000 00000000`00000000 : prl_fs+0x2d393
ffffd000`21a6d5d0 fffff800`8921ebb1 : fffff800`892112e0 ffffe001`f0659600 ffffe001`f14705c0 ffffe001`ef2ec040 : prl_fs+0xa841
ffffd000`21a6d6c0 fffff800`89204b77 : ffffe001`f14705c0 ffffe001`f14705c0 ffffe001`f0659680 ffffe001`f0659680 : prl_fs+0x1ebb1
ffffd000`21a6d6f0 fffff800`88c083cd : ffffe001`f14705c0 00000000`00000000 fffff800`88c05010 ffffe001`ee36b8a0 : prl_fs+0x4b77
ffffd000`21a6d720 fffff800`8861ccf8 : ffffd000`21a6d860 00000000`00000000 ffffc000`78ab6770 00000000`00000000 : mup!MupFsdIrpPassThrough+0x1ee
ffffd000`21a6d7a0 fffff800`8861b0b6 : ffffe001`eeea7df0 ffffe001`f0659680 ffffe001`f14705c0 fffff800`8861fcdf : fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x258
ffffd000`21a6d840 fffff800`76c238ec : 00000000`00000001 ffffd000`21a6d921 ffffe001`f0659680 fffff800`88645ac1 : fltmgr!FltpDispatch+0xb6
ffffd000`21a6d8a0 fffff800`76c23298 : ffffe001`f0659604 ffffe001`f0659680 ffffe001`f0d4afe0 ffffe001`f0659680 : nt!IopSynchronousServiceTail+0x16c
ffffd000`21a6d970 fffff800`7697d7b3 : ffffe001`f1ad5801 00000000`00003918 00000000`00000000 00000000`224ffd90 : nt!NtWriteFile+0x750
ffffd000`21a6da90 00007ff8`68f6ac0a : 00007ff8`66363979 00000000`224ffd90 00000000`00000001 00000000`ffffffff : nt!KiSystemServiceCopyEnd+0x13
00000000`3700cfc8 00007ff8`66363979 : 00000000`224ffd90 00000000`00000001 00000000`ffffffff 00000000`224ffd60 : ntdll!NtWriteFile+0xa
00000000`3700cfd0 00007ff8`66387e0e : 00000000`5b500000 00000000`5b500000 00000000`00000008 00000000`00000000 : KERNELBASE!WriteFile+0x10c
00000000`3700d050 00007ff8`663861eb : 00000000`00004001 00000000`00000002 00000000`48200000 00000000`00000000 : KERNELBASE!BaseCopyStream+0x9c8
00000000`3700df00 00007ff8`663df751 : 00000000`229ad198 00000000`3700e508 00000000`000002a8 00007ff8`66e42c2d : KERNELBASE!BasepCopyFileExW+0x74f
00000000`3700e4e0 00007ff8`66c99a8e : 00000000`2feb8b50 00000000`80070bea 00000000`00000000 ffffffff`ffffffff : KERNELBASE!CopyFile2+0xd9
00000000`3700e5a0 00007ff8`6706e2be : 00000000`00000000 00000000`00000000 00000000`00000000 00007ff8`66c84ac9 : SHELL32!CFSTransfer::_PerformCopyFileWithRetry+0xde
00000000`3700e650 00007ff8`66c84317 : 00000000`3700e9e0 00000000`00000000 00000000`2fe61228 00000000`229ae000 : SHELL32!CFSTransfer::CopyItem+0x23a
00000000`3700e6c0 00007ff8`66c840f8 : 00000000`223116c0 00000000`226f26f0 00000000`226f26f0 00000000`3700e860 : SHELL32!CCopyOperation::_CreateDestinationOrCopyItemWithRetry+0x9b
00000000`3700e760 00007ff8`66a66bf9 : 00000000`22256680 00000000`12ca0c40 00000000`226f26f0 00000000`12ca0c40 : SHELL32!CCopyOperation::Do+0x134
00000000`3700ea40 00007ff8`66a67806 : 00000000`12ca0c40 00000000`12ca0c40 00000000`3700eb40 00000000`226f26f0 : SHELL32!CCopyWorkItem::_DoOperation+0x49
00000000`3700eab0 00007ff8`66a697db : 00000000`12ca0c40 00000000`12ca0c40 00000000`3700eef0 00000000`00000000 : SHELL32!CCopyWorkItem::_SetupAndPerformOp+0x23a
00000000`3700edf0 00007ff8`66a69645 : 00000000`14a2e780 00000000`14a2e780 00000000`14a2e780 00000000`14a2e780 : SHELL32!CCopyWorkItem::ProcessWorkItem+0x14b
00000000`3700f0b0 00007ff8`66a67d6f : 00000000`2fe61228 00000000`2fe61228 00000000`00000000 00000000`14a2e780 : SHELL32!CRecursiveFolderOperation::Do+0x195
00000000`3700f150 00007ff8`66a6919c : 00000000`3022e9f0 00000000`3700f259 00000000`3022eb28 00000000`00000000 : SHELL32!CFileOperation::_EnumRootDo+0x23b
00000000`3700f1f0 00007ff8`66a6f212 : 00000000`00000000 00000000`00000000 00000000`3022e9f0 00000000`3022ea00 : SHELL32!CFileOperation::PrepareAndDoOperations+0x19c
00000000`3700f2c0 00007ff8`6707f37e : 00000000`222e2f28 00000000`00000001 00000000`00000000 00000000`144f7430 : SHELL32!CFileOperation::PerformOperations+0xd2
00000000`3700f310 00007ff8`6707d96e : 00000000`226f03f0 00000000`226f03f0 00000000`00000000 00000000`144f7430 : SHELL32!CFSDropTargetHelper::_MoveCopyHIDA+0x232
00000000`3700f3c0 00007ff8`6707ff2a : 00000000`00000052 00000000`144f7430 00000000`00000000 00000000`00000048 : SHELL32!CFSDropTargetHelper::_Drop+0x2be
00000000`3700f690 00007ff8`64bd8023 : 00000000`00000001 00000000`00000001 00000000`00000000 00000000`00000000 : SHELL32!CFSDropTargetHelper::s_DoDropThreadProc+0x3e
00000000`3700f6c0 00007ff8`68c9168d : 00000000`24a3c480 00000000`00000000 00000000`00000000 00000000`00000000 : SHCORE!Microsoft::WRL::FtmBase::MarshalInterface+0x17b
00000000`3700f7e0 00007ff8`68f44629 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0xd
00000000`3700f810 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d

Posted in WinDbg | Tagged | Leave a comment

Continuing Case of ByRef Corruption–.NET Patching

A new revision of app we previously met here http://chentiangemalc.wordpress.com/2014/05/22/case-of-the-invalid-base-key-error/ was out…

The “Invalid Base Key” error had been patched, but now we had another. It looked like another case of variables being unexpectedly modified due to liberal and incorrect use of By Reference.

I also noticed the recommendation to change ByRef into ByVal hadn’t been followed. Instead…

if (szBaseKey.ToString() == “”)
{
  Information.Err().Raise(-2147220989, “RegIni Class”, “Invalid Base Key”, null, null);
}

had been replaced with

if (szBaseKey.ToString() == “”)
{
}

Certainly eliminated the error message though.

In this new case however it seemed multiple API calls may be impacted. Majority of them were called by a function called QueryValue. So I wanted to change that function to use it’s parameters “by value” instead of “by reference”

Using ILDasm from Windows SDK I decompiled the EXE, and it was easy enough to patch the function definition to use “by value” I just had to remove the ampersands:

From

.method public instance object  QueryValue(int32& lhKey,
                                             string& szKeyName,
                                             string& szValueName,
                                             [opt] bool& bSupressErrorMessage) cil managed noinlining nooptimization
 

to

.method public instance object  QueryValue(int32 lhKey,
                                             string szKeyName,
                                             string szValueName,
                                             [opt] bool bSupressErrorMessage) cil managed noinlining nooptimization
 


However this also requires updating all the calls to the method. To easily do this you want a text editor that supports multi-line search & replace. In this case I used UltraEdit (http://www.ultraedit.com/downloads/ultraedit_download.html)

image

I had to do this twice as calls to this function had been formatted in two different ways. To ensure none were let I searched for QueryValue(int32&

With that we recompiled our IL file. This was .NET 2.0 app so I used .NET 2.0 version of ilasm:

c:\windows\microsoft.net\framework\v2.0.50727\ilasm.exe qfbox2.il /resource=qfbox2.res

However the fresh EXE didn’t work:

image

Using Visual Studio I set Debug –> Exceptions and ticked all boxes

image

Then launched EXE with Visual Studio .NET Reflector add-in “Debug an Executable”

image

then

image

Looking at this we can see our bSupressErrorMessage had been turned into an array. This is because accessing the “by reference” value different code gets generated.

For example this C# code:

public object QueryValue(ref int lhKey,ref string szKeyName, ref string szValueName,ref bool bSupressErrorMessage) { if (!bSupressErrorMessage) { Console.WriteLine("by reference: bSupressErrorMessage NOT true"); } return null; } public object QueryValue(int lhKey, string szKeyName, string szValueName, bool bSupressErrorMessage) { if (!bSupressErrorMessage) { Console.WriteLine("by value: bSupressErrorMessage NOT true"); } return null; }

Generates the following IL code:

.method public hidebysig instance object QueryValue(int32& lhKey, string& szKeyName, string& szValueName, bool& bSupressErrorMessage) cil managed { .maxstack 1 .locals init ( [0] object obj2, [1] bool flag) L_0000: nop L_0001: ldarg.s bSupressErrorMessage L_0003: ldind.i1 L_0004: stloc.1 L_0005: ldloc.1 L_0006: brtrue.s L_0015 L_0008: nop L_0009: ldstr "by reference: bSupressErrorMessage NOT true" L_000e: call void [mscorlib]System.Console::WriteLine(string) L_0013: nop L_0014: nop L_0015: ldnull L_0016: stloc.0 L_0017: br.s L_0019 L_0019: ldloc.0 L_001a: ret } .method public hidebysig instance object QueryValue(int32 lhKey, string szKeyName, string szValueName, bool bSupressErrorMessage) cil managed { .maxstack 1 .locals init ( [0] object obj2, [1] bool flag) L_0000: nop L_0001: ldarg.s bSupressErrorMessage L_0003: stloc.1 L_0004: ldloc.1 L_0005: brtrue.s L_0014 L_0007: nop L_0008: ldstr "by value: bSupressErrorMessage NOT true" L_000d: call void [mscorlib]System.Console::WriteLine(string) L_0012: nop L_0013: nop L_0014: ldnull L_0015: stloc.0 L_0016: br.s L_0018 L_0018: ldloc.0 L_0019: ret }

In both cases we can see a local variable is created

[1] bool flag

Then bSupressErrorMessage argument is loaded onto the stack:

ldarg.s bSupressErrorMessage

Now only the “by reference” version performs:

ldind.i1 (Loads a value of type int8 as an int32 onto the evaluation stack indirectly.)

Then both versions continue the same:

Pops the current value from the top of the evaluation stack and stores it in a the local variable list at index 1. (This saving our argument into the bool flag)

stloc.1

Loads the local variable at index 1 onto the evaluation stack.

ldloc.1

Transfers control to a target instruction (short form) if value is true, not null, or non-zero.

brtrue.s <target>

In our crashing code we found:

IL_012c:  ldarg.s    bSupressErrorMessage
    IL_012e:  ldind.i1
    IL_012f:  ldc.i4.0
    IL_0130:  ceq
    IL_0132:  stloc.s    V_10
    IL_0134:  ldloc.s    V_10
 

We removed the

ldind.i1

We can double check our patch with .NET reflector, we can see the [0] is gone…

image

And the app no longer crashes…

Posted in .NET, Hacking, MSIL, Patching | Tagged | Leave a comment

Launching .NET EXE extracted from Memory DMP

Using the SOS debugging extension (http://msdn.microsoft.com/en-us/library/bb190764(v=vs.110).aspx) we can easily save modules in a .NET memory dump.

I wanted to do some runtime analysis of an EXE, but I only had dmp file.

0:000> .load C:\windows\microsoft.net\Framework64\v2.0.50727\sos.dll
0:000> lmv m qfbox2
start             end                 module name
00000000`00e20000 00000000`00e40000   QFBox2     (deferred)            
    Image path: C:\QIK-QUBE2\QFB\QFBox2.exe
    Image name: QFBox2.exe
    Has CLR image header, track-debug-data flag not set
    Timestamp:        Thu May 15 16:54:56 2014 (537464C0)
    CheckSum:         00000000
    ImageSize:        00020000
    File version:     2.0.1.3
    Product version:  2.0.1.3
    File flags:       0 (Mask 3F)
    File OS:          4 Unknown Win32
    File type:        1.0 App
    File date:        00000000.00000000
    Translations:     0000.04b0
    CompanyName:      Company
    ProductName:      QIK Function Box
    InternalName:     QFBox2.exe
    OriginalFilename: QFBox2.exe
    ProductVersion:   2.0.1.3
    FileVersion:      2.0.1.3
    FileDescription:  QIK Function Box
    LegalCopyright:   Company
0:000> !SaveModule 00000000`00e20000 C:\support\qfbox2.exe
4 sections in file
section 0 – VA=2000, VASize=16254, FileAddr=400, FileSize=16400
section 1 – VA=1a000, VASize=5d, FileAddr=16800, FileSize=200
section 2 – VA=1c000, VASize=1350, FileAddr=16a00, FileSize=1400
section 3 – VA=1e000, VASize=c, FileAddr=17e00, FileSize=200

OK great, we can now explore EXE easily with tool like .NET reflector or ILDasm as-is.

But trying to launch EXE we get error:

image

Via WinDbg

image

To resolve this issue:

1. Decompile with ILDasm Windows SDK. In ILDasm click File –> Open select EXE, then File –> Dump, leave defauts, and click OK.

2. Recompile with ILasm, under Microsoft.NET directories, specify .res file output by ILDasm. Because this is .NET 2.0 app I used ILAsm from .NET 2.0 folder.

c:\windows\microsoft.net\framework\v2.0.50727\ilasm.exe qfbox2.il /resource=qfbox2.res /x64

In this case app failed to launch:

image

In WinDbg:

ModLoad: 00007ffd`8d860000 00007ffd`8d86a000   C:\Windows\Microsoft.NET\Framework64\v2.0.50727\culture.dll
(20b0.17a0): CLR exception – code e0434f4d (first chance)
(20b0.17a0): CLR exception – code e0434f4d (!!! second chance !!!)
KERNELBASE!RaiseException+0x68:
00007ffd`8fc568d8 488b8c24c0000000 mov     rcx,qword ptr [rsp+0C0h] ss:00000000`0050f560=000048ce57469afc
0:000> kv
Child-SP          RetAddr           : Args to Child                                                           : Call Site
00000000`0050f4a0 00007ffd`87fd5acf : 00000000`00739a40 00000000`0240f680 00000000`0050f5d0 00000000`00739a40 : KERNELBASE!RaiseException+0x68
00000000`0050f580 00007ffd`88138daf : 00000000`0240f680 00007ffd`00000000 00000000`00000000 00000000`00000001 : mscorwks!RaiseTheExceptionInternalOnly+0x2ff
00000000`0050f670 00007ffd`88392eec : ffffffff`fffffffe 00000000`0050db80 00007c0c`00000000 00000000`00000000 : mscorwks!UnwindAndContinueRethrowHelperAfterCatch+0x63
00000000`0050f6d0 00007ffd`88847cfd : ffffffff`ffffffff 00000000`00739a40 00000000`00000000 00000000`0050f6d8 : mscorwks! ?? ::FNODOBFM::`string’+0xa006c
00000000`0050f730 00007ffd`888fea5b : 00000000`00000000 00007ffd`880c44c4 00000000`00000000 00000000`00000000 : mscoreei!CorExeMain+0xe0
00000000`0050f780 00007ffd`9024168d : 00007ffd`88840000 00000000`00000000 00000000`00000000 00000000`00000000 : MSCOREE!CorExeMain_Exported+0xcb
00000000`0050f7b0 00007ffd`92554629 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0xd
00000000`0050f7e0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
0:000> .load C:\windows\microsoft.net\Framework64\v2.0.50727\SOS.dll
0:000> !Printexception
Exception object: 000000000240f680
Exception type: System.BadImageFormatException
Message: Could not load file or assembly ‘qfbox2.exe’ or one of its dependencies. An attempt was made to load a program with an incorrect format.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 8007000b

So I recompile with the following options:

c:\windows\microsoft.net\framework\v2.0.50727\ilasm.exe qfbox2.il /resource=qfbox2.res

Note: If we wanted debug version with PDBs we could also add

ilasm.exe qfbox2.il /resource=qfbox2.res /debug /pdb

OK application now launches:

image

However, it is running 32-bit :

image

To fix that we run corflags.exe from Windows SDK.

Note: Windows 7 SDK v7.0A (.NET 3.5) and earlier use /PE32- instead of /32BITREQ-

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools>corflags C:\qik-qube2\qfb\qfbox2.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.33440

Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 0x3
ILONLY    : 1
32BITREQ  : 1
32BITPREF : 0
Signed    : 0

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools>corflags C:\qik-qube2\qfb\qfbox2.exe /32BITREQ-
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.33440

Copyright (c) Microsoft Corporation.  All rights reserved.

C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools>corflags C:\qik-qube2\qfb\qfbox2.exe
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.0.30319.33440

Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v2.0.50727
CLR Header: 2.5
PE        : PE32
CorFlags  : 0x1
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 0
Signed    : 0

We can see it is now running as 64-bit.

image

Note:

After rebooting my system for Windows Updates using /x64 ILASM option worked fine. In addition without /x64 option the EXE directly compiled to x64 without needing corflags to change it. I couldn’t reproduce this issue again.

Using DumpBin.exe /headers from Windows SDK we compared what was different between the two process:

EXE Dumped from DMP Recompiled EXE
machine (x86)
(It was an x64 EXE)
machine (x64)
4 number of sections 3 number of sections
102 characteristics 22 characteristics
16400 size of code 16200 size of code
0 entry point 1819E entry point
1 Debug Directory None
Summary

 

2000 .reloc
2000 .rsrc
18000 .text

Summary

2000 .reloc
2000 .rsrc
2000 .sdata
18000 .text

Posted in .NET, 64-bit, WinDbg | Tagged | Leave a comment

Case of the Group Policy Preference Fail

A customer had an issue with mail not appearing in their Inbox. Their Exchange team had advised to set a registry value under HKEY_CURRENT_USER\Software\Policies\Microsoft\Office15.0\Outlook\Options\mail

A group policy had been created to set the value, and it successfully worked on five test users. However after widespread deployment many users failed to receive the setting.

Using ProcMon with a filter to include Path Contains Software\Policies\Microsoft\Office15.0\Outlook\Options\mail we could see when gpupdate was run the result was ACCESS DENIED.

This is due to the fact the policy was set to apply current user keys “as the user”

By default users do not have write access to to keys under HKCU\Policies

While they have write access to SOFTWARE

image

Under Policies they only have Read access. This is to ensure a non-admin user can’t just run a script to remove/change their user based policies.

image

The reason it worked on the test users is they had all been from the IT department and all had local admin. That’s a bad idea, although not a new one.( http://chentiangemalc.wordpress.com/2012/04/12/an-epic-battle-of-adobe-vs-ie-vs-sap/ )

In this case the solution was not to deploy the Policies key via Group Policy Preferences. As it is a “Policies” key we downloaded the Office ADMX files from Microsoft Website (http://www.microsoft.com/en-us/download/details.aspx?id=35554) and set the policy that way.

We confirmed this fixed the issue.

What if I only knew the registry key but not the policy name? You can use this technique to quickly find it http://chentiangemalc.wordpress.com/2014/03/25/finding-prevent-performance-of-first-run-wizard-in-windows-8-1-group-policy/

Posted in Group Policy | Tagged | Leave a comment

Importing Reg Files Into Group Policy Preferences

Surprisingly there doesn’t seem to be any obvious way to import “reg” files into Group Policy Preferences. And using the Registry Import Wizard can be tedious ticking many many tick boxes.

Looking around existing tools I could find one commercial tool but nothing freely available, so put together a PowerShell script to convert a .REG file to a .XML file that can be dragged and dropped into a Group Policy Preference.

This script supports the following registry types:

  • REG_DWORD
  • REG_QWORD
  • REG_EXPAND_SZ
  • REG_MULTI_SZ
  • REG_BINARY
  • REG_SZ

Note: Your reg file should contain data from one hive only (i.e. HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE) as the Group Policy preference XML doesn’t allow two hive types.

Usage:

Convert-Reg2Xml -regPath input.reg -xmlPath output.xml

Then drag and drop XML file into the registry section of Group Policy preference editor.

(Tested on Windows Server 2012 R2 only, but expect it to work on other servers/clients)

Note: There is pretty much no error checking currently in script. It is assumed reg file is exported from reg edit. If you manually created reg file with slight differences from reg edit export this tool may not process reg file correctly.

Script can be downloaded here: https://onedrive.live.com/redir?resid=93A8E9D387076121!1388&authkey=!AJFuJBPvhP5vAyk&ithint=file%2c.zip

function Convert-RegEscapeCodes { Param( [Parameter(Position=1)][string]$regstring) return $regstring.Replace("\\","\").Replace('\"','"') } function Convert-Reg2Xml { Param( [Parameter(Mandatory=$True)][string]$regPath, [Parameter(Mandatory=$True)][string]$xmlPath ) $clsidCollection = "{53B533F5-224C-47e3-B01B-CA3B3F3FF4BF}" $clsidRegistry = "{9CD4B2F4-923D-47f5-A062-E897DD1DAD50}" $settings = New-Object System.Xml.XmlWriterSettings $settings.Indent=$True $settings.Encoding = [System.Text.Encoding]::UTF8 $xml = [System.Xml.XmlWriter]::Create($xmlPath,$settings) $descr = "Imported Reg File" $action = "U" $unicoder = New-Object System.Text.UnicodeEncoding $lastHive=""; $lastKey=""; $sr=New-Object System.IO.StreamReader($regPath) $lastHive="" $lastKey="" $collectionCount=0 while (!$sr.EndOfStream) { $line = $sr.ReadLine() if ($line.StartsWith("[")) { $currentHive=$line.Substring(1,$line.IndexOf("\")-1) $currentKey=$line.Substring($line.IndexOf("\")+1,$line.Length-$line.IndexOf("\")-2) if ($lastHive -eq "") { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$currentHive) $collectionCount++ ForEach ($key in $currentKey.Split('\')) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$key) $collectionCount++ } } else { # hives don't match - settings.xml doesn't support this! if ($currentHive -ne $lastHive) { # invalid - settings.xml only supports one HIVE type per file Throw "Reg file format is not supported by settings .XML. Please use only $currentHive or $lastHive per XML file" return } else { # going up a key if ($currentKey.StartsWith($lastKey + "\")) { $newKey=$currentKey.Substring($lastKey.Length+1) ForEach ($key in $newKey.Split('\')) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$key) $collectionCount++ } } else { # funky logic to handle change in key path # maybe this logic even works :) $currentKeySplit=$currentKey.Split('\') $lastKeySplit=$lastKey.Split('\') $match=$true $i=-1 while ($match) { $i++ if ($i -ge $currentKeySplit.Length -or $i -ge $lastKeySplit.Length) { $match=$false } else { if ($currentKeySplit[$i] -ne $lastKeySplit[$i]) { $match=$false } } } for ($x=$lastKeySplit.Length;$x -gt $i;$x--) { $xml.WriteEndElement() $collectionCount-- } for ($x=$i;$x -lt $currentKeySplit.Length;$x++) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$currentKeySplit[$x]) $collectionCount++ } } } } $lastHive=$currentHive $lastKey=$currentKey } else { if ($line.Contains("=")) { $regType=[Microsoft.Win32.RegistryValueKind]::Unknown # detect registry type if ($line.StartsWith("@=") -or $line.Contains('"="')) { $regType=[Microsoft.Win32.RegistryValueKind]::String } if ($line.Contains("=hex:")) { $regType=[Microsoft.Win32.RegistryValueKind]::Binary } if ($line.Contains("=dword:")) { $regType=[Microsoft.Win32.RegistryValueKind]::DWord } if ($line.Contains("=hex(7):")) { $regType=[Microsoft.Win32.RegistryValueKind]::MultiString } if ($line.Contains("=hex(2):")) { $regType=[Microsoft.Win32.RegistryValueKind]::ExpandString } if ($line.Contains("=hex(b):")) { $regType=[Microsoft.Win32.RegistryValueKind]::QWord } switch ($regType) { # *** PROCESS REG_SZ ([Microsoft.Win32.RegistryValueKind]::String) { $default="0" if ($line.StartsWith("@=")) { $valueName="" $value=$line.Substring(3,$line.Length-4) "Name = '$valueName' Value = '$value'" $default="1" } else { $i = $line.IndexOf('"="') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=Convert-RegEscapeCodes $line.Substring($i+3,$line.Length-$i-4) "Name = '$valueName' Value = '$value'" } $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default",$default) $xml.WriteattributeString("type","REG_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_BINARY ([Microsoft.Win32.RegistryValueKind]::Binary) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } $i = $line.IndexOf('"=hex:') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+6).Replace(",","") "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_BINARY") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_DWORD ([Microsoft.Win32.RegistryValueKind]::DWord) { $i = $line.IndexOf('"=dword:') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+8).ToUpper() "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_DWORD") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_QWORD ([Microsoft.Win32.RegistryValueKind]::QWord) { $i = $line.IndexOf('"=hex(b):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $tempValue=$line.Substring($i+9).Replace(",","").ToUpper() $value="" # unreverse QWORD for settings.xml format for ($i = $tempValue.Length -2;$i -gt 0;$i-=2) { $value+=$tempValue.Substring($i,2) } "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_QWORD") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROESS REG_MULTI_MZ ([Microsoft.Win32.RegistryValueKind]::MultiString) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } # read hex codes $i = $line.IndexOf('"=hex(7):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+9).Replace(",","") # convert hex codes to binary array $byteLength=$value.Length/2 $byte = New-Object Byte[] $byteLength $x=0 for ($i=0;$i -lt $value.Length;$i+=2) { $byte[$x]="0x" + $value.Substring($i,2) $x++ } # convert binary array to unicode string $value=$unicoder.GetString($byte) # retrieve multi values $values=$value.Replace("`0`0","").Split("`0") "Name = '$valueName'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_MULTI_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value.Replace("`0"," ")) $x=1 $xml.WriteStartElement("Values") ForEach ($value in $values) { $xml.WriteStartElement("Value") $xml.WriteString($value) "Value $x = '$value'" $xml.WriteEndElement() } $xml.WriteEndElement() $xml.WriteEndElement() $xml.WriteEndElement() } ([Microsoft.Win32.RegistryValueKind]::ExpandString) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } # read hex codes $i = $line.IndexOf('"=hex(2):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+9).Replace(",","") # convert hex codes to binary array $byteLength=$value.Length/2 $byte = New-Object Byte[] $byteLength $x=0 for ($i=0;$i -lt $value.Length;$i+=2) { $byte[$x]="0x" + $value.Substring($i,2) $x++ } # convert binary array to unicode string $value=$unicoder.GetString($byte).Replace("`0","") "Name = '$valueName' Value = '$value'" $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default",$default) $xml.WriteattributeString("type","REG_EXPAND_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } } } } } $sr.Close() while ($collectionCount -gt 0) { $xml.WriteEndElement() $collectionCount-- } $xml.Close() } Convert-Reg2Xml -regPath "C:\support\ReceiverCSTRegUpx64.reg" -xmlPath C:\support\Citrix.xmlfunction Convert-RegEscapeCodes { Param( [Parameter(Position=1)][string]$regstring) return $regstring.Replace("\\","\").Replace('\"','"') } function Convert-Reg2Xml { Param( [Parameter(Mandatory=$True)][string]$regPath, [Parameter(Mandatory=$True)][string]$xmlPath ) $clsidCollection = "{53B533F5-224C-47e3-B01B-CA3B3F3FF4BF}" $clsidRegistry = "{9CD4B2F4-923D-47f5-A062-E897DD1DAD50}" $settings = New-Object System.Xml.XmlWriterSettings $settings.Indent=$True $settings.Encoding = [System.Text.Encoding]::UTF8 $xml = [System.Xml.XmlWriter]::Create($xmlPath,$settings) $descr = "Imported Reg File" $action = "U" $unicoder = New-Object System.Text.UnicodeEncoding $lastHive=""; $lastKey=""; $sr=New-Object System.IO.StreamReader($regPath) $lastHive="" $lastKey="" $collectionCount=0 while (!$sr.EndOfStream) { $line = $sr.ReadLine() if ($line.StartsWith("[")) { $currentHive=$line.Substring(1,$line.IndexOf("\")-1) $currentKey=$line.Substring($line.IndexOf("\")+1,$line.Length-$line.IndexOf("\")-2) if ($lastHive -eq "") { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$currentHive) $collectionCount++ ForEach ($key in $currentKey.Split('\')) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$key) $collectionCount++ } } else { # hives don't match - settings.xml doesn't support this! if ($currentHive -ne $lastHive) { # invalid - settings.xml only supports one HIVE type per file Throw "Reg file format is not supported by settings .XML. Please use only $currentHive or $lastHive per XML file" return } else { # going up a key if ($currentKey.StartsWith($lastKey + "\")) { $newKey=$currentKey.Substring($lastKey.Length+1) ForEach ($key in $newKey.Split('\')) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$key) $collectionCount++ } } else { # funky logic to handle change in key path # maybe this logic even works :) $currentKeySplit=$currentKey.Split('\') $lastKeySplit=$lastKey.Split('\') $match=$true $i=-1 while ($match) { $i++ if ($i -ge $currentKeySplit.Length -or $i -ge $lastKeySplit.Length) { $match=$false } else { if ($currentKeySplit[$i] -ne $lastKeySplit[$i]) { $match=$false } } } for ($x=$lastKeySplit.Length;$x -gt $i;$x--) { $xml.WriteEndElement() $collectionCount-- } for ($x=$i;$x -lt $currentKeySplit.Length;$x++) { $xml.WriteStartElement("Collection") $xml.WriteAttributeString("clsid",$clsidCollection) $xml.WriteAttributeString("name",$currentKeySplit[$x]) $collectionCount++ } } } } $lastHive=$currentHive $lastKey=$currentKey } else { if ($line.Contains("=")) { $regType=[Microsoft.Win32.RegistryValueKind]::Unknown # detect registry type if ($line.StartsWith("@=") -or $line.Contains('"="')) { $regType=[Microsoft.Win32.RegistryValueKind]::String } if ($line.Contains("=hex:")) { $regType=[Microsoft.Win32.RegistryValueKind]::Binary } if ($line.Contains("=dword:")) { $regType=[Microsoft.Win32.RegistryValueKind]::DWord } if ($line.Contains("=hex(7):")) { $regType=[Microsoft.Win32.RegistryValueKind]::MultiString } if ($line.Contains("=hex(2):")) { $regType=[Microsoft.Win32.RegistryValueKind]::ExpandString } if ($line.Contains("=hex(b):")) { $regType=[Microsoft.Win32.RegistryValueKind]::QWord } switch ($regType) { # *** PROCESS REG_SZ ([Microsoft.Win32.RegistryValueKind]::String) { $default="0" if ($line.StartsWith("@=")) { $valueName="" $value=$line.Substring(3,$line.Length-4) "Name = '$valueName' Value = '$value'" $default="1" } else { $i = $line.IndexOf('"="') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=Convert-RegEscapeCodes $line.Substring($i+3,$line.Length-$i-4) "Name = '$valueName' Value = '$value'" } $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default",$default) $xml.WriteattributeString("type","REG_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_BINARY ([Microsoft.Win32.RegistryValueKind]::Binary) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } $i = $line.IndexOf('"=hex:') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+6).Replace(",","") "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_BINARY") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_DWORD ([Microsoft.Win32.RegistryValueKind]::DWord) { $i = $line.IndexOf('"=dword:') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+8).ToUpper() "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_DWORD") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROCESS REG_QWORD ([Microsoft.Win32.RegistryValueKind]::QWord) { $i = $line.IndexOf('"=hex(b):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $tempValue=$line.Substring($i+9).Replace(",","").ToUpper() $value="" # unreverse QWORD for settings.xml format for ($i = $tempValue.Length -2;$i -gt 0;$i-=2) { $value+=$tempValue.Substring($i,2) } "Name = '$valueName' Value = '$value'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","17") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_QWORD") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } # *** PROESS REG_MULTI_MZ ([Microsoft.Win32.RegistryValueKind]::MultiString) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } # read hex codes $i = $line.IndexOf('"=hex(7):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+9).Replace(",","") # convert hex codes to binary array $byteLength=$value.Length/2 $byte = New-Object Byte[] $byteLength $x=0 for ($i=0;$i -lt $value.Length;$i+=2) { $byte[$x]="0x" + $value.Substring($i,2) $x++ } # convert binary array to unicode string $value=$unicoder.GetString($byte) # retrieve multi values $values=$value.Replace("`0`0","").Split("`0") "Name = '$valueName'" # build XML $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default","0") $xml.WriteattributeString("type","REG_MULTI_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value.Replace("`0"," ")) $x=1 $xml.WriteStartElement("Values") ForEach ($value in $values) { $xml.WriteStartElement("Value") $xml.WriteString($value) "Value $x = '$value'" $xml.WriteEndElement() } $xml.WriteEndElement() $xml.WriteEndElement() $xml.WriteEndElement() } ([Microsoft.Win32.RegistryValueKind]::ExpandString) { # read binary key to end while ($line.EndsWith("\")) { $line=$line.Substring(0,$line.Length-1)+$sr.ReadLine().Trim() } # read hex codes $i = $line.IndexOf('"=hex(2):') $valueName=Convert-RegEscapeCodes $line.Substring(1,$i-1) $value=$line.Substring($i+9).Replace(",","") # convert hex codes to binary array $byteLength=$value.Length/2 $byte = New-Object Byte[] $byteLength $x=0 for ($i=0;$i -lt $value.Length;$i+=2) { $byte[$x]="0x" + $value.Substring($i,2) $x++ } # convert binary array to unicode string $value=$unicoder.GetString($byte).Replace("`0","") "Name = '$valueName' Value = '$value'" $xml.WriteStartElement("Registry") $xml.WriteAttributeString("clsid",$clsidRegistry) $xml.WriteAttributeString("name",$valueName) $xml.WriteAttributeString("descr",$descr) $xml.WriteAttributeString("image","7") $xml.WriteStartElement("Properties") $xml.WriteAttributeString("action",$action) $xml.WriteAttributeString("hive",$currentHive) $xml.WriteAttributeString("key",$currentKey) $xml.WriteattributeString("name",$valueName) $xml.WriteattributeString("default",$default) $xml.WriteattributeString("type","REG_EXPAND_SZ") $xml.WriteattributeString("displayDecimal","0") $xml.WriteAttributeString("value",$value) $xml.WriteEndElement() $xml.WriteEndElement() } } } } } $sr.Close() while ($collectionCount -gt 0) { $xml.WriteEndElement() $collectionCount-- } $xml.Close() } Convert-Reg2Xml -regPath "input.reg" -xmlPath output.xml

Posted in Group Policy, PowerShell | Tagged , | Leave a comment

Upgrade EXE .NET Framework with ILDasm, ILAsm and Hex Editor

Previously we have “upgraded” the .NET framework of an EXE by modifying/creating the <EXE name>.config file

<supportedRuntime version=”v4.0″/>

As per here: http://msdn.microsoft.com/en-us/library/w4atty68(v=vs.110).aspx

Now we will cover an alternative method. This technique is easy with a simple executable that only loads in-built .NET libraries. If the EXE loads 3rd party DLLs compiled to an older .NET framework the process may become complicated.

First we dump our IL code with ILDasm, included with Visual Studio:

image

Default dump options are OK.

image

In this case we have a .NET 2.0 app, so in the .assembly extern sections we replace .ver 2:0:0:0 with .ver 4:0:0:0 and leave other versioned DLLs alone.

We then compile the IL file:

C:\Windows\Microsoft.NET\Framework\v4.0.30319>ilasm <path to filename>

OK exe is now running .NET v4.0 version. We can see this with Process Explorer:

image

What about .NET v4.5?

To do that we need to perform the above changes, but also insert within the assembly definition

.assembly <name of assembly>
{

}

The following line:

.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 1A 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ....NETFramework 2C 56 65 72 73 69 6F 6E 3D 76 34 2E 35 01 00 54 // ,Version=v4.5..T 0E 14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C // ..FrameworkDispl 61 79 4E 61 6D 65 12 2E 4E 45 54 20 46 72 61 6D // ayName..NET Fram 65 77 6F 72 6B 20 34 2E 35 )

 

OK what about a .NET 1.1 app?

Like the Delphi 8 Borland Pascal .NET Compiler:

image

This takes me to site:

http://dotnetsocial.cloudapp.net/GetDotnet?tfm=v1.1.4322&processName=dccil.exe&platform=0009&osver=6&isServer=0&shimver=4.0.30319.34014

image

But only has downloads for .NET 3.5 and later…

Examining EXE we can see it is not a MSIL based executable, but instead uses CorBindToRuntimeEx (http://msdn.microsoft.com/en-us/library/99sz37yh(v=vs.110).aspx) to load the .NET runtime.

From the documentation we can see a string is passed with .NET version to load. Using a Hex editor (A good one for Windows here: http://hexedit.com/ Just be careful you download the actual program not the ADware )

In this case upgrading to v4.0.30319 is problematic as the string is longer than the original, and is challenging to insert longer string into binary. However luckily for us immediately following the version text is the “wks” value, which is also passed into the function. Our patching job is made much easier due to the fact A NULL value for this parameter will default to wks.

Leaving our patched bytes looking like this:

image

I also search for a UNICODE version of same string, and also update it, finishing with double 00 at end of string.

image

Posted in .NET | Leave a comment