Case of the Application Guard Code Integrity / Windows Lockdown Policy Crash

Some categories of applications started crashing after no obvious system changes had been. As an initial step user mode crash dumps were collecting following the guide at Collecting User-Mode Dumps – Win32 apps | Microsoft Docs with DumpType set to 2.

Opening dump file in WinDbg ( WinDbg Preview – Installation – Windows drivers | Microsoft Docs ) the initial dump file showed a CLR runtime exception, so we know we have a .NET exception.

This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(6f8.2358): CLR exception - code e0434352 (first/second chance not available)
For analysis of this file, run !analyze -v
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000003 edi=00000003
eip=77a723dc esp=00afc4a8 ebp=00afc638 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
ntdll!NtWaitForMultipleObjects+0xc:
77a723dc c21400          ret     14h
0:000>

As this was a .NET 4.0+ app we can load the SOS debugging extension with the following cmd, and evaluate the exceptions thrown

0:000> .loadby sos clr
0:000> !pe
Exception object: 02c75fdc
Exception type:   System.TypeInitializationException
Message:          The type initializer for '<Module>' threw an exception.
InnerException:   System.TypeInitializationException, Use !PrintException ad4b1278 to see more.
StackTrace (generated):
    SP       IP       Function
    00000000 00000001 MyApp!ns10.App.OnStartup(System.Windows.StartupEventArgs)+0x2
    00AFEA94 54E02EF2 PresentationFramework_ni!System.Windows.Application.<.ctor>b__1_0(System.Object)+0x2e
    00AFEAA4 56C4EE42 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)+0x52
    00AFEAC4 56C4ED85 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)+0x35
    00AFEB08 56C510CD WindowsBase_ni!System.Windows.Threading.DispatcherOperation.InvokeImpl()+0xdd
    00AFEB40 56C4F56F WindowsBase_ni!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(System.Object)+0x3f
    00AFEB48 72F68604 mscorlib_ni!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xc4
    00AFEBB4 72F68537 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0x17
    00AFEBC8 72F684F4 mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)+0x44
    00AFEBE0 56C50F83 WindowsBase_ni!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext, System.Threading.ContextCallback, System.Object)+0xe3
    00AFEC10 56C50D80 WindowsBase_ni!System.Windows.Threading.DispatcherOperation.Invoke()+0x50
    00AFEC44 56C4D346 WindowsBase_ni!System.Windows.Threading.Dispatcher.ProcessQueue()+0x176
    00AFEC84 56C4C57C WindowsBase_ni!System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0x5c
    00AFECD0 56C4E661 WindowsBase_ni!MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)+0xa1
    00AFED0C 56C4E94C WindowsBase_ni!MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)+0x6c
    00AFED1C 56C4EE42 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)+0x52
    00AFED3C 56C4ED85 WindowsBase_ni!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)+0x35
    00AFED80 56C4CF62 WindowsBase_ni!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)+0x142
    00AFEDDC 56C4E4B4 WindowsBase_ni!MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)+0xf4
    00000000 00000001 WindowsBase_ni!MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)+0x2
    00AFF010 56C4B3D7 WindowsBase_ni!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)+0xbb
    00AFF058 56C4B319 WindowsBase_ni!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)+0x4d
    00AFF064 54E02EBC PresentationFramework_ni!System.Windows.Application.RunDispatcher(System.Object)+0x60
    00AFF074 54E02A7A PresentationFramework_ni!System.Windows.Application.RunInternal(System.Windows.Window)+0x7a
    00AFF094 54E0286E PresentationFramework_ni!System.Windows.Application.Run(System.Windows.Window)+0x2e
    00AFF0A4 02A90885 MyApp!ns10.App.Main()+0x3d

StackTraceString: <none>
HResult: 80131534
0:000> !PrintException /d 02c746dc
Exception object: 02c746dc
Exception type:   System.TypeInitializationException
Message:          The type initializer for 'A.c0d8b631f41631263c838860696e4f989' threw an exception.
InnerException:   System.IO.FileLoadException, Use !PrintException ad4b1278 to see more.
StackTrace (generated):
    SP       IP       Function
    00000000 00000001 UNKNOWN!A.c0d8b631f41631263c838860696e4f989.c930e960a62160e11b812c53c9297a8e3()+0x2
    00AFCDA0 02A9C979 UNKNOWN!<Module>..cctor()+0x9

StackTraceString: <none>
HResult: 80131534
0:000> !PrintException /d 02c72cf4
Exception object: 02c72cf4
Exception type:   System.IO.FileLoadException
Message:          Could not load file or assembly 'MyApp&' or one of its dependencies. Exception from HRESULT: 0xD0000003
InnerException:   System.IO.FileLoadException, Use !PrintException ad4b1278 to see more.
StackTrace (generated):
    SP       IP       Function
    00000000 00000001 mscorlib_ni!System.Reflection.RuntimeAssembly._nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)+0xffffffff8bf056e1
    00AFC590 72F70776 mscorlib_ni!System.Reflection.RuntimeAssembly.nLoad(System.Reflection.AssemblyName, System.String, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)+0x26
    00AFC5B4 72F5B610 mscorlib_ni!System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(System.Reflection.AssemblyName, System.Security.Policy.Evidence, System.Reflection.RuntimeAssembly, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean, Boolean, Boolean)+0xa0
    00AFC5EC 72F5EEF5 mscorlib_ni!System.Reflection.RuntimeAssembly.InternalLoad(System.String, System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef, IntPtr, Boolean)+0x51
    00AFC610 72F5EE9F mscorlib_ni!System.Reflection.RuntimeAssembly.InternalLoad(System.String, System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef, Boolean)+0x17
    00AFC61C 72F5AFF6 mscorlib_ni!System.Reflection.Assembly.Load(System.String)+0x1e
    00AFC628 02A9CA35 UNKNOWN!A.c0d8b631f41631263c838860696e4f989..cctor()+0xa5

StackTraceString: <none>
HResult: d0000003
0:000> !PrintException /d 02c6fcb0
Exception object: 02c6fcb0
Exception type:   System.IO.FileLoadException
Message:          Could not load file or assembly '4608 bytes loaded from MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Exception from HRESULT: 0xD0000003
InnerException:   System.Runtime.InteropServices.COMException, Use !PrintException ad4b1278 to see more.
StackTrace (generated):
    SP       IP       Function
    00000000 00000001 mscorlib_ni!System.Reflection.RuntimeAssembly.nLoadImage(Byte[], Byte[], System.Security.Policy.Evidence, System.Threading.StackCrawlMark ByRef, Boolean, Boolean, System.Security.SecurityContextSource)+0xffffffff8baefbd1
    00AF9BE4 73705AC7 mscorlib_ni!System.Reflection.Assembly.Load(Byte[])+0x2f
    00AF9BF4 02A9CB26 UNKNOWN!A.c0d8b631f41631263c838860696e4f989.c38bdfea66bcae865ec581807b0e136d1(System.Object, System.ResolveEventArgs)+0x56
    00AF9C08 72F97305 mscorlib_ni!System.AppDomain.OnAssemblyResolveEvent(System.Reflection.RuntimeAssembly, System.String)+0x99

StackTraceString: <none>
HResult: d0000003

A few things we can learn from this:

  • We are dealing with an obfuscated .NET module due to the random GUID function names
  • Due to “filename” in message Could not load file or assembly containing a xxx bytes loaded message that tells us that a .NET assembly is trying to be loaded from memory, probably extracted as a resource
  • The resource name we can find from message Could not load file or assembly ‘MyApp&’
  • Couldn’t find any documented reference for meaning of HRESULT d0000003

We can try and extract the module from the dump file with SaveModule command of sos extension:

0:000> lmvm MyApp
Browse full module list
start    end        module name
001b0000 006ac000   MyApp   (no symbols)           
    Loaded symbol image file: MyApp.exe
    Image path: C:\Program Files (x86)\Application\MyApp.exe
    Image name: MyApp.exe
    Browse all global symbols  functions  data
    Has CLR image header, track-debug-data flag not set
    Timestamp:        Thu Dec 11 05:18:31 2018 (605347F4)
    CheckSum:         005E6981
    ImageSize:        004FC000
    File version:     1.0.0.0
    Product version:  1.0.0.0
    File flags:       0 (Mask 3F)
    File OS:          4 Unknown Win32
    File type:        1.0 App
    File date:        00000000.00000000
    Translations:     0000.04b0
    Information from resource tables:
        CompanyName:      My Company
        ProductName:      MyApp
        InternalName:     MyApp.exe
        OriginalFilename: MyApp.exe
        ProductVersion:   1.0.0
        FileVersion:      1.0.0.0
        FileDescription:  My Company
        LegalCopyright:   © My Company 2018
0:000> !SaveModule 001b0000 C:\debug\MyApp.exe
3 sections in file
section 0 - VA=2000, VASize=4ea2b4, FileAddr=200, FileSize=4ea400
section 1 - VA=4ee000, VASize=ad60, FileAddr=4ea600, FileSize=ae00
section 2 - VA=4fa000, VASize=c, FileAddr=4f5400, FileSize=200

We can now analyze the .NET assembly with standard .NET decompiling tools such as:

With these tools we can see the EXEs have what looks to be an encrypted file matching the name shown in crash dump in the .NET resources table, with the application module’s name followed by an ampersand i.e.. MyApp&.

Generally I think it’s a good idea to have several different tools as some more complex executables get better results from different tools in different scenarios.

However the code in this functions crashing looks like complete gibberish due to the obfuscation.

Using de4dot/de4dot: .NET deobfuscator and unpacker. (github.com) we are able to “deobfuscate” the module.

De4dot detects that the app has been protected with Crypto Obfuscator For .Net – Obfuscator With Code Protection, Exception Reporting, Optimization For .Net Assemblies, WPF, Silverlight, Windows Phone 7 and ASP.Net Websites (ssware.com)

Once deobfuscated the application no longer crashes.

So why is it crashing?

To further analyze this we took a Time Travel Debugging trace from within WinDbg ( Time Travel Debugging – Introduction to Time Travel Debugging objects – Windows drivers | Microsoft Docs )

Unfortunately the trace didn’t capture the application crash exception, instead only had the following exception:

Break instruction exception - code 80000003 (first/second chance not available)

In order to avoid this we had to take the TTD trace without using WinDbg. From a machine where WinDbg Preview had been installed using Windows store I copied the executable files out and into another directory. If you are unable to access the files you may need to run from an elevated command prompt, or a command prompt running as system account.

Once copied out you should be able to use without installing on Windows 8 or Server 2012 and later.

From an elevated command prompt we could then start trace with comand

\amd64\TTD\ttd.exe -launch <application name> <application arguments>

OR

\amd64\TTD\ttd.exe -attach <process id>

This approach generated a suitable trace with many .NET exceptions present in the trace.

Once loaded we loaded sos extension as before, and in addition as with most .NET traces we also loaded Steve’s Techspot – SOSEX v4.0 Now Available (stevestechspot.com) as this is especially more intuitive at setting breakpoints than with SOS extension (And many advanced features)

To automatically break on all .NET exceptions we used command and hit g to continue

sxe e0434352
g

This took us to the same load exception we had in our crash dump file. But now being a TTD we can work backwards to get a more detailed root cause.

We want to find where the very first exception got raised. From a stack we can see function clr!UnwindAndContinueRethrowHelperAfterCatch

0:000> k
 # ChildEBP RetAddr      
00 0095b324 769840b2     ntdll!RtlRaiseException
01 0095b38c 741528f0     KERNELBASE!RaiseException+0x62
02 0095b428 741bc1a2     clr!RaiseTheExceptionInternalOnly+0x230
03 0095b45c 7451070b     clr!UnwindAndContinueRethrowHelperAfterCatch+0x6f
04 0095b518 73705ac7     clr!AssemblyNative::LoadImage+0x23c
05 0095b53c 10d80a06     mscorlib_ni!System.Reflection.Assembly.Load(Byte[])$##600426B+0x2f

We set a breakpoint on this function and went backwards. I used bm with wildcards as I found it more reliable to hit the breakpoints especially when not having access to full debugging symbols.:

0:000> bm clr!UnwindAndContinueRethrowHelperAfterCatch*
  1: 741bc149          @!"clr!UnwindAndContinueRethrowHelperAfterCatch"
0:000> g-
Breakpoint 1 hit
Time Travel Position: 2B3419:AF5
eax=745106f9 ebx=0095b50c ecx=74033450 edx=10f47e10 esi=7476f1d0 edi=0095b50c
eip=741bc149 esp=0095b460 ebp=0095b518 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!UnwindAndContinueRethrowHelperAfterCatch:
741bc149 6a0c            push    0Ch

I used t- command to step backwards one instruction at a time, looking for when the exception HRESULT we originally got d0000003 was being set or any other clues. Once we hit a function in VCRUNTIME140_CLR0400 we could see other exception related functions in the stack.

VCRUNTIME140_CLR0400!_SEH_epilog4+0x12:
7403e8e8 51              push    ecx
0:000> K
 # ChildEBP RetAddr      
00 00959b60 74033304     VCRUNTIME140_CLR0400!_SEH_epilog4+0x12
01 00959b88 74032ebc     VCRUNTIME140_CLR0400!CatchIt+0x65
02 00959c04 74032c33     VCRUNTIME140_CLR0400!FindHandler+0x27e
03 00959c30 7403e6a6     VCRUNTIME140_CLR0400!__InternalCxxFrameHandler+0xf2
04 00959c6c 77a88e72     VCRUNTIME140_CLR0400!__CxxFrameHandler+0x26
05 00959c90 77a88e44     ntdll!ExecuteHandler2+0x26
06 00959d58 77a742d6     ntdll!ExecuteHandler+0x24
07 0095a278 00000000     ntdll!KiUserExceptionDispatcher+0x26

We went backwards to this function using the same approach as before:

:000> bm ntdll!KiUserExceptionDispatcher*
  2: 77a742b0          @!"ntdll!KiUserExceptionDispatcher"
0:000> g-
Breakpoint 2 hit
Time Travel Position: 2B33F9:0
eax=00000000 ebx=0095a2dc ecx=00000000 edx=00000000 esi=740314a4 edi=747906d0
eip=77a742b0 esp=00959d68 ebp=0095a278 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
ntdll!KiUserExceptionDispatcher:
77a742b0 833d4ce9b17700  cmp     dword ptr [ntdll!LdrDelegatedKiUserExceptionDispatcher (77b1e94c)],0 ds:002b:77b1e94c=00000000

We followed same approach using t- and then a later stack showed a suitable function in stack so we went to it.

0:000> bm VCRUNTIME140_CLR0400!_CxxThrowException*
  4: 74034600          @!"VCRUNTIME140_CLR0400!_CxxThrowException"
0:000> g-
(1c20.1c90): C++ EH exception - code e06d7363 (first/second chance not available)
Breakpoint 4 hit
Time Travel Position: 2B33F5:1BA
eax=0095a2dc ebx=00004000 ecx=00004000 edx=00000000 esi=d0000003 edi=10f47e10
eip=74034600 esp=0095a2c0 ebp=0095a710 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
VCRUNTIME140_CLR0400!_CxxThrowException:
74034600 55              push    ebp

Using same approach we find another target function:

0:000> bm clr!EEFileLoadException::Throw*
  5: 74365044          @!"clr!EEFileLoadException::Throw"
  6: 74364c7a          @!"clr!EEFileLoadException::Throw"
  7: 743648d1          @!"clr!EEFileLoadException::Throw"
  8: 743646cf          @!"clr!EEFileLoadException::Throw"
  9: 74364e24          @!"clr!EEFileLoadException::Throw"
 10: 74364ad0          @!"clr!EEFileLoadException::Throw"
0:000> g-
Breakpoint 5 hit
Time Travel Position: 2B32F8:769
eax=d0000003 ebx=10f4a320 ecx=10f27b00 edx=00000000 esi=7410fc70 edi=10f4a320
eip=74365044 esp=0095a714 ebp=0095b314 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
clr!EEFileLoadException::Throw:
74365044 6828040000      push    428h

When we go backwards from this function we finally see our HRESULT code for the first time in EAX register, within clr!PEAssembly::OpenMemory function.

0:000> t-
Time Travel Position: 2B32F8:766
eax=d0000003 ebx=10f4a320 ecx=10f4a320 edx=00000000 esi=7410fc70 edi=10f4a320
eip=743adda9 esp=0095a71c ebp=0095b314 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
clr!PEAssembly::OpenMemory+0xd5:
743adda9 ff7508          push    dword ptr [ebp+8]    ss:002b:0095b31c=00261600
0:000> t-
Time Travel Position: 2B32F8:765
eax=d0000003 ebx=10f4a320 ecx=10f4a320 edx=00000000 esi=7410fc70 edi=10f4a320
eip=743adda8 esp=0095a720 ebp=0095b314 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
clr!PEAssembly::OpenMemory+0xd4:
743adda8 50              push    eax

We go back until we find where EAX was set to this HRESULT:

0:000> t-
Time Travel Position: 2B32F8:763
eax=7406abf4 ebx=10f4a320 ecx=10f4a320 edx=00000000 esi=7410fc70 edi=10f4a320
eip=7410fc70 esp=0095a71c ebp=0095b314 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
clr!SecurityContextFrame::GetAssembly:
7410fc70 8b4108          mov     eax,dword ptr [ecx+8] ds:002b:10f4a328=d0000003

This is telling us that memory location 10f4a328 holds our HRESULT value. To find when this is set we set a break point on memory write access to this location and go backwards. I also clear my existing breakpoints first incase these exception functions I had breakpoints on got hit multiple times while going back.

0:000> bc *
0:000> ba w 1 10f4a328
0:000> g-
(1c20.1c90): C++ EH exception - code e06d7363 (first/second chance not available)
(1c20.1c90): C++ EH exception - code e06d7363 (first/second chance not available)
Breakpoint 0 hit
Time Travel Position: 2B32BC:C8
eax=00000000 ebx=00261600 ecx=0000000c edx=00000000 esi=d0000003 edi=10f4a320
eip=7452b793 esp=0095af54 ebp=0095af74 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
clr!ThrowHR+0x76:
7452b793 8885fcffffff    mov     byte ptr [ebp-4],al        ss:002b:0095af70=01
0:000> t-
Time Travel Position: 2B32BC:C7
eax=00000000 ebx=00261600 ecx=0000000c edx=00000000 esi=d0000003 edi=10f4a320
eip=7452b790 esp=0095af54 ebp=0095af74 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
clr!ThrowHR+0x76:
7452b790 897708          mov     dword ptr [edi+8],esi ds:002b:10f4a328=00000000

We now also have a more interesting stack trace:

0:000> k
 # ChildEBP RetAddr      
00 0095af74 744cf18f     clr!ThrowHR+0x51
01 0095af84 744cf5f8     clr!PEImageLayout::CheckCodeIntegrity+0x5f
02 0095b1ec 743c4127     clr!RawImageLayout::RawImageLayout+0x17d
03 0095b230 743adf4c     clr!PEImage::LoadFlat+0x70
04 0095b2a4 743adccb     clr!PEAssembly::DoOpenMemory+0x43
05 0095b314 7450fc23     clr!PEAssembly::OpenMemory+0x4b
06 0095b438 74510608     clr!AssemblyNative::LoadFromBuffer+0x479
07 0095b518 73705ac7     clr!AssemblyNative::LoadImage+0x166

We now set a breakpoint on clr!ThrowHR and go backwards…

0:000> bm clr!ThrowHR*
  2: 7452b710          @!"clr!ThrowHR"
  4: 7452b7ff          @!"clr!ThrowHR"
  5: 7452b8ba          @!"clr!ThrowHR"
0:000> g-
Breakpoint 2 hit
Time Travel Position: 2B32A4:B
eax=d0000003 ebx=00261600 ecx=d0000003 edx=00000000 esi=66873640 edi=10efbe90
eip=7452b710 esp=0095af78 ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!ThrowHR:
7452b710 6a04            push    4

Finally when we hit t- we are now in the function where exception was thrown:

0:000> t-
Time Travel Position: 2B32A4:A
eax=d0000003 ebx=00261600 ecx=d0000003 edx=00000000 esi=66873640 edi=10efbe90
eip=744cf18a esp=0095af7c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!PEImageLayout::CheckCodeIntegrity+0x5a:
744cf18a e881c50500      call    clr!ThrowHR (7452b710)

We can see that the exception was thrown if EAX <> 0:

Time Travel Position: 2B32A4:A
eax=d0000003 ebx=00261600 ecx=d0000003 edx=00000000 esi=66873640 edi=10efbe90
eip=744cf18a esp=0095af7c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!PEImageLayout::CheckCodeIntegrity+0x5a:
744cf18a e881c50500      call    clr!ThrowHR (7452b710)
0:000> t-
Time Travel Position: 2B32A4:9
eax=d0000003 ebx=00261600 ecx=00000000 edx=00000000 esi=66873640 edi=10efbe90
eip=744cf188 esp=0095af7c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!PEImageLayout::CheckCodeIntegrity+0x58:
744cf188 8bc8            mov     ecx,eax
0:000> t-
Time Travel Position: 2B32A4:8
eax=d0000003 ebx=00261600 ecx=00000000 edx=00000000 esi=66873640 edi=10efbe90
eip=744cf17b esp=0095af7c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!PEImageLayout::CheckCodeIntegrity+0x4b:
744cf17b 780b            js      clr!PEImageLayout::CheckCodeIntegrity+0x58 (744cf188) [br=1]
0:000> t-
Time Travel Position: 2B32A4:7
eax=d0000003 ebx=00261600 ecx=00000000 edx=00000000 esi=66873640 edi=10efbe90
eip=744cf179 esp=0095af7c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
clr!PEImageLayout::CheckCodeIntegrity+0x49:
744cf179 85c0            test    eax,eax

One more step backwards and we find what triggered our failure:

0:000> t-
Time Travel Position: 2B32A4:6
eax=d0000003 ebx=00261600 ecx=00000000 edx=00000000 esi=66873640 edi=10efbe90
eip=66873696 esp=0095af6c ebp=0095af84 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
wldp!WldpQueryDynamicCodeTrust+0x56:
66873696 c20c00          ret     0Ch
0:000> lmvm wldp
Browse full module list
start    end        module name
66860000 66882000   wldp       (pdb symbols)          C:\ProgramData\Dbg\sym\WLDP.pdb\04DF37356E1254CDAE5C6B767C1E8B7E1\WLDP.pdb
    Loaded symbol image file: wldp.dll
    Mapped memory image file: C:\ProgramData\Dbg\sym\wldp.dll\DF4FDF2C22000\wldp.dll
    Image path: C:\windows\SYSTEM32\wldp.dll
    Image name: wldp.dll
    Browse all global symbols  functions  data
    Image was built with /Brepro flag.
    Timestamp:        DF4FDF2C (This is a reproducible build file hash, not a timestamp)
    CheckSum:         0002D5ED
    ImageSize:        00022000
    File version:     10.0.18362.295
    Product version:  10.0.18362.295
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft® Windows® Operating System
        InternalName:     wldp.dll
        OriginalFilename: wldp.dll
        ProductVersion:   10.0.18362.295
        FileVersion:      10.0.18362.295 (WinBuild.160101.0800)
        FileDescription:  Windows Lockdown Policy
        LegalCopyright:   © Microsoft Corporation. All rights reserved.

Essentially loading the encrypted DLL from within a resource of an EXE in memory, instead of off the disk, triggered a Windows Lockdown Policy that was configured to strictly enforce code integrity.

Looking up function documentation WldpQueryDynamicCodeTrust function (Wldp.h) – Win32 apps | Microsoft Docs we can see it states the following:

Retrieves a value that determines if the specified in-memory or on-disk .NET CRL dynamic code is trusted by Device Guard policy.

Exceptions to the lockdown policy would be required for this application to continue to work as-is or the software developer would need to either remove the obfuscation or work with the vendor providing the obfuscation software to ensure it was compatible with this Windows configuration.

Now that we know this is where the fault lies further details can be extracted from the Windows code integrity log, for example using PowerShell:

Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" | Out-GridView

Or In Windows Event Viewer under Windows Logs -> Application and Service Logs -> Microsoft -> Windows -> CodeIntegrity -> Operational

More verbose logging can be obtained from Event Viewer by selecting View -> Show Analytic and Debug Logs and right clicking the CodeIntegrity -> Verbose log and selecting enable. It is recommended to disable once finished collecting trace as it may cause a performance hit on your system.

About chentiangemalc

specializes in end-user computing technologies. disclaimer 1) use at your own risk. test any solution in your environment. if you do not understand the impact/consequences of what you're doing please stop, and ask advice from somebody who does. 2) views are my own at the time of posting and do not necessarily represent my current view or the view of my employer and family members/relatives. 3) over the years Microsoft/Citrix/VMWare have given me a few free shirts, pens, paper notebooks/etc. despite these gifts i will try to remain unbiased.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment