Dot Net Callstack From Windbg

16 Feb 2020

Recently I experienced a bug with Git Extensions and I did not yet have JitMagic set up with dnSpy integration. I needed the callstack to report an issue to the developers.

I chose WinDbg as the just-in-time debugger. And simply ran !analyze -v:

*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *

DEBUG_FLR_EXCEPTION_CODE(80131509) and the ".exr -1" ExceptionCode(e0434352) don't match
MethodDesc:   00007ffc4ae31d70
Method Name:  System.Reactive.Concurrency.SynchronizationContextScheduler.Schedule[[System.ValueTuple`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]], System.ValueTuple]](System.ValueTuple`2<System.__Canon,System.__Canon>, System.Func`3<System.Reactive.Concurrency.IScheduler,System.ValueTuple`2<System.__Canon,System.__Canon>,System.IDisposable>)
Class:        00007ffc7f601a38
MethodTable:  00007ffc7fed5ba0
mdToken:      00000000060011ac
Module:       00007ffc7f3b1000
IsJitted:     yes
CodeAddr:     00007ffc4ad2e360
Transparency: Critical
GetUrlPageData2 (WinHttp) failed: 12007.


    Key  : CLR.System.InvalidOperationException._message
    Value: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.



Timeline: !analyze.Start
    Name: <blank>
    Time: 2020-02-16T21:23:49.402Z
    Diff: 402 mSec

Timeline: Dump.Current
    Name: <blank>
    Time: 2020-02-16T21:23:49.0Z
    Diff: 0 mSec

Timeline: Process.Start
    Name: <blank>
    Time: 2020-02-16T21:17:54.0Z
    Diff: 355000 mSec

Timeline: OS.Boot
    Name: <blank>
    Time: 2020-02-16T13:48:23.0Z
    Diff: 27326000 mSec



00007ffc`b7e7908c 488b8c24c0000000 mov     rcx,qword ptr [rsp+0C0h]

ExceptionAddress: 00007ffcb7e7908c (KERNELBASE!RaiseException+0x0000000000000068)
   ExceptionCode: e0434352 (CLR exception)
  ExceptionFlags: 00000001
NumberParameters: 5
   Parameter[0]: ffffffff80131509
   Parameter[1]: 0000000000000000
   Parameter[2]: 0000000000000000
   Parameter[3]: 0000000000000000
   Parameter[4]: 00007ffcaa250000


EXCEPTION_CODE: (HRESULT) 0x80131509 (2148734217) - <Unable to get error code text>








WATSON_BKT_MODVER:  6.3.9600.19425

MODULE_VER_PRODUCT:  Microsoft® Windows® Operating System

BUILD_VERSION_STRING:  9600.19629.amd64fre.winblue_ltsb_escrow.200127-1700

MODLIST_WITH_TSCHKSUM_HASH:  642958e44b66935a181d61b4c64e4bdbaa672d71

MODLIST_SHA1_HASH:  abdd8c7f6b6b349838b6e46c74e36108e0c55c11








PROCESS_NAME:  unknown



ANALYSIS_SESSION_TIME:  02-16-2020 22:23:49.0402

ANALYSIS_VERSION: 10.0.17763.132 amd64fre






LAST_CONTROL_TRANSFER:  from 00007ffcaa26a451 to 00007ffcb7e7908c

THREAD_SHA1_HASH_MOD_FUNC:  496307919b5c20eda4b6b1d7f8f57fe40ecc2624

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  27cfc7cdea8e40dd4dc3a7ebac53d16e2aeb6dac


BUGCHECK_STR:  CLR_EXCEPTION_System.InvalidOperationException

DEFAULT_BUCKET_ID:  CLR_EXCEPTION_System.InvalidOperationException



    ID:     [0n254]
    Type:   [CLR_EXCEPTION]
    Class:  Primary
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
    Name:   Add
    Data:   Omit
    PID:    [Unspecified]
    TID:    [0x10d4]
    Frame:  [0] : KERNELBASE!RaiseException

    ID:     [0n252]
    Type:   [@ManagedObjectName]
    Class:  Addendum
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
    Name:   Omit
    Data:   Add
            String: [System.InvalidOperationException]
    PID:    [0x2f30]
    TID:    [Unspecified]
    Frame:  [0]

00000003`dc8eec80 00007ffc`91ef1173 System_Windows_Forms_ni!System.Windows.Forms.Control.MarshaledInvoke+0x3d3
00000003`dc8eedc0 00007ffc`91ef0c72 System_Windows_Forms_ni!System.Windows.Forms.Control.BeginInvoke+0x62
00000003`dc8eee30 00007ffc`92972b71 System_Windows_Forms_ni!System.Windows.Forms.WindowsFormsSynchronizationContext.Post+0x51
00000003`dc8eee80 00007ffc`4ad2e47b System_Reactive_ni!System.Reactive.Concurrency.SynchronizationContextScheduler.Schedule[[System.ValueTuple_2[[System.__Canon,_mscorlib],[System.__Canon,_mscorlib]],_System.ValueTuple]]+0x11b
00000003`dc8eeef0 00007ffc`7fb379b4 System_Reactive_ni!System.Reactive.Concurrency.Scheduler.ScheduleAction[[System.__Canon,_mscorlib]]+0x154
00000003`dc8eef70 00007ffc`7fc56771 System_Reactive_ni!System.Reactive.Linq.ObservableImpl.EventProducer_2+Session+__c[[System.__Canon,_mscorlib],[System.__Canon,_mscorlib]]._Connect_b__5_0+0xf1
00000003`dc8eeff0 00007ffc`7fc623e2 System_Reactive_ni!System.Reactive.Disposables.AnonymousDisposable_1[[System.ValueTuple_3[[System.__Canon,_mscorlib],[System.__Canon,_mscorlib],[System.__Canon,_mscorlib]],_System.ValueTuple]].Dispose+0x82
00000003`dc8ef050 00007ffc`7fb3478e System_Reactive_ni!System.Reactive.Disposables.Disposable.TryDispose+0x5e
00000003`dc8ef090 00007ffc`7fc49314 System_Reactive_ni!System.Reactive.Linq.ObservableImpl.Throttle_1+_[[System.__Canon,_mscorlib]].Dispose+0x24
00000003`dc8ef0c0 00007ffc`7fb4797b System_Reactive_ni!System.Reactive.Sink_1[[System.__Canon,_mscorlib]].Dispose+0xab
00000003`dc8ef120 00007ffc`7fb3478e System_Reactive_ni!System.Reactive.Disposables.Disposable.TryDispose+0x5e
00000003`dc8ef160 00007ffc`7fb49003 System_Reactive_ni!System.Reactive.ObserveOnObserverNew_1[[System.__Canon,_mscorlib]].Dispose+0x23
00000003`dc8ef1a0 00007ffc`7fb4797b System_Reactive_ni!System.Reactive.Sink_1[[System.__Canon,_mscorlib]].Dispose+0xab
00000003`dc8ef200 00007ffc`81b9697b GitUI_ni!GitUI.CommitInfo.CommitInfoHeader.DisposeCustomResources+0x1b
00000003`dc8ef230 00007ffc`81aa6643 GitUI_ni!GitUI.GitModuleControl.Dispose+0x53
00000003`dc8ef270 00007ffc`a8233371 System_ni!System.ComponentModel.Component.Finalize+0x11

STACK_COMMAND:  ! 0x3c4b0ff98 ; ** Pseudo Context ** ManagedPseudo ** Value: 534961d8e0 ** ; kb

THREAD_SHA1_HASH_MOD:  15163896b4156cc0a0208a3b87e3d5d6d3923e94

00007ffc`91ef1173 90              nop



SYMBOL_NAME:  System_Windows_Forms_ni!System.Windows.Forms.Control.MarshaledInvoke+2c1173

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: System_Windows_Forms

IMAGE_NAME:  System.Windows.Forms.dll


FAILURE_BUCKET_ID:  CLR_EXCEPTION_System.InvalidOperationException_80131509_System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke

BUCKET_ID:  CLR_EXCEPTION_System.InvalidOperationException_System_Windows_Forms_ni!System.Windows.Forms.Control.MarshaledInvoke+2c1173


FAILURE_IMAGE_NAME:  System.Windows.Forms.dll

BUCKET_ID_IMAGE_STR:  System.Windows.Forms.dll

FAILURE_MODULE_NAME:  System_Windows_Forms

BUCKET_ID_MODULE_STR:  System_Windows_Forms

FAILURE_FUNCTION_NAME:  System.Windows.Forms.Control.MarshaledInvoke

BUCKET_ID_FUNCTION_STR:  System.Windows.Forms.Control.MarshaledInvoke






BUCKET_ID_PREFIX_STR:  CLR_EXCEPTION_System.InvalidOperationException_


FAILURE_SYMBOL_NAME:  System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke


TARGET_TIME:  2020-02-16T21:23:56.000Z

OSBUILD:  9600





OSNAME:  Windows 8.1

OSEDITION:  Windows 8.1 WinNt SingleUserTS


OSBUILD_TIMESTAMP:  2019-10-15 05:45:31


BUILDLAB_STR:  winblue_ltsb_escrow

BUILDOSVER_STR:  6.3.9600.19629.amd64fre.winblue_ltsb_escrow.200127-1700




FAILURE_ID_HASH:  {c279e3a4-dab2-09ec-a135-2281bfa61101}

Followup:     MachineOwner

Everything was magically analyzed and I was able to open an issue. As an added bonus I recently worked to allowing dnSpy to be used as a JIT debugger from JitMagic:

dnSpy JIT

Best regards,


Leave a comment

Not Analyzing Keyboard Firmware Part 3

25 Nov 2019

In the first post I briefly discussed my motivation to analyze the keyboard’s firmware and I did make a small amount of progress since last time (thanks to /u/thoquz who suggested to try SVD Loader), but unfortunately other projects required my attention and I didn’t think there was enough (interesting) progress to report. However I did make significant progress towards solving my actual problem (a caps lock macro layer), so I decided to share that here as well!

The macro layer

The solution I came up with is based on AutoHotkey, which I heard about but never actually used myself before. For those not familiar, AutoHotkey allows you to create system-wide hotkeys in a custom scripting language. It is a bit weird, but it can apparently do crazy things, so why not give it a try?

After a while of thinking and experimenting I came up with the following key map (thanks to Keyboard Layout Editor. Green is the macro layer, the rest is just for reference:

macro layer

Initially I just had the arrows + home/end, but while doing some actual programming work I came up with a bunch of other useful things. For example Caps+G(it) is bound to F13, which I linked in Visual Studio to start my GitExtBar utility:


Similarly I bound Caps+E(xplore) to my DirBrowser utility in Visual Studio, which allows me to quickly open the project’s output directory in Total Commander or a command prompt:


A bunch of C++ related symbols are also bound to this layer, so I can keep holding caps lock when closing an if-block. I also bound Caps+S/D to scroll the mouse wheel, something I always appreciate in my browser with Saka Key. Finally Alt is also used for quickly navigating. For Left/Right it acts as Ctrl (meaning Caps+Alt+J maps to Ctrl+Left), for Home/End it acts as Shift (meaning Caps+Alt+U maps to Shift+Home).

If you are interested you can find a snapshot of capslayer.ahk here. I set up a cloud sync service and a hotkey to quickly reload the script to make sure things work the same across my various computers. Additionally I run the script as Administrator on login to make sure it is always available everywhere.

Beating old habits

Even though my macro layer was working perfectly I still found myself using the arrows and home/end keys over the macro keys all the time. Because I think the macro layer will be a more economic way of typing in the long run I decided to completely disable the original keys (which thankfully is super easy with AutoHotkey). This was quite a pain for a few days at work, but I can now (proudly?) say that I am typing utter garbage on other machines.

Generally I noticed that when it comes to forming habits on your computer, you should always use that same computer to simply enforce what you want to learn and punish old habits. Want to take more breaks? Simply configure Workrave to not allow you to continue and block all inputs. Want to get yourself in the habit of using Total Commander (which, frankly, you should if you value your time as a professional using Windows), use AutoHotkey to redirect Win+E to start Total Commander. Want to browse social media less? Use StayFocusd.

The future

If time permits and interest comes back I will definitely continue analyzing the keyboard firmware, because I did learn a lot from the short amount of time I spent on it so far. However, for my daily needs I will keep fine-tuning this AutoHotkey-based solution because it is so much easier. I did already find Karabiner-Elements for macOS, which should allow similar things, so I will play with that a bit before my trip next month.

Please let me know if you have any questions or suggestions with regards to my workflow and have a good week!


Leave a comment

Analyzing Keyboard Firmware Part 2

13 Oct 2019

In last post we looked at obtaining the firmware for my new keyboard. I downloaded the firmware update utility and extracted a firmware image. The next step will be to set up the tooling and try to build a hello world as a point of reference.

I think the first step to any reverse engineering project should be to try and understand how the software you are reverse engineering was developed. Things like the libraries and compilers involved are very important, because without that frame of reference you might waste a lot of time on unimportant implementation details. If you are interested there is a great talk by Alex Ionescu called Reversing Without Reversing that goes more in depth about this topic.

The tools

Now the tricky part about writing a post like this is that it takes hours of research (downloading files, trying different things), but in the end it can be represented as a simple list:

  • Download and install Keil MDK-ARM (you can get an evaluation version);
  • Install the pack for the SN32F240;
  • Download and install;
  • Open the project in Keil uVision5;
  • Hit build.

Pretty much all of the information (including the download links) can be found on the SN32F40 product page. Initially I was having some issues having to be logged in to download the starter kit, but that got magically resolved and from there it was easy.

Installing Keil MDK-ARM is straightforward, just fill in the evaluation form and run the installer. You can then use PackInstaller.exe to search for and install the SN32F240 pack (alternatively you can use SONiX.SN32F2_DFP.1.2.11.pack from the starter kit):

toolkit installation

You then need to install SONiX’ proprietary Hex2Bin utility and open SN32F240_Startkit_Package_V3.4R\CMSIS Firmware Library_V3.2\USB_Library_For_64K_V1.5\SN32F240_Demo.uvprojx in the IDE and hit build (F7). If you did everything right you should see something like:

HexConvertVer = V24
CheckSum = 0xAC6E
".\obj\SN32F240.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:01

Now if you take a look in the obj directory there are two interesting files: SN32F240.BIN and SN32F240.axf. The .BIN file is a firmware image very similar to the one extracted earlier and the .axf is a regular ELF file.


If you have been living under a rock you might not know that the NSA released their reverse engineering suite called Ghidra a while back. I tried it out a little, but didn’t really have a use case yet so I decided to try and use it for this project. I also tried IDA and it worked fine on the ELF file, but it was a total mess setting up the memory map and getting references to work so I decided to stick with Ghidra.

There was also a bug with Ghidra 9.0.2, so I will be using the 9.1-BETA_DEV version. Now all left to do is create a project in Ghidra, import SN32F240.axf and load it in the CodeBrowser:


Next steps

In the next post we will take a look at the firmware initialization routines and use the information obtained from the ELF file and the datasheet to be able to properly load and analyze the extracted keyboard firmware. The posts are a bit short for my taste right now, but I do not have that much time to spend on this project so I think it allows me to write more consistently like this.

Best regards,


Thanks again to F. for the proofread!

Leave a comment

Analyzing Keyboard Firmware Part 1

28 Sep 2019

Recently I bought a cheap SPC Gear GK530 mechanical keyboard to test out the Kailh Brown keyswitches. Overall it has a nice feel and you can change the epic RGB-lights to just be a dimmed constant color so I would recommend it for typing.

Unfortunately the macro/rebind feature is not very much to my liking. Right now you have to switch to Gaming mode (FN+Win) and then you can use use your modified keymap (with macros). In this mode you cannot use the Windows key (because it is locked) and it is generally quite awkward.

My preferred mode would be that holding Caps Lock enables my custom layer, which unfortunately does not seem to be supported. At this point I thought it would be a fun project to try and hack the firmware to support this behavior.


Obtaining the firmware

Luckily for us SPC Gear provides two firmware update utilities on their Software page. The utility is called 1 - GK530 keyboard upgrade.exe and when I started it I was reminded of a similar utility I took at look at in the past.

firmware upgrade

The similar utility was a firmware upgrade tool for my current keyboard:

similar utility

When looking at a firmware upgrade tool in the past I documented it on a Github issue. From a quick glance it appears that nothing has changed, except that the firmware is no longer ‘encypted’ now and the UI looks a bit more fancy.

To obtain the image:

  • Extract the "BINARY" resource (170). You can use CFF Explorer for this task.
  • The extracted blob is an executable with no functionality, which has an ‘overlay’ appended to it (data after the end of the last section).
  • The overlay is the firmware image (65k) with some additional metadata at the end.


The interesting string there is at the very end, which says SN32F24x (all SONiX chips seem to start with SN). With a bit of Google-fu and creativity you can land on the product page for the SN32F248. Over there you can also find a bunch of links to utilities and manuals, one of which is called SONiX_USB_MCU_ISP_Tool_V2. Opening the extracted firmware yields a good result:

original flash tool

Additionally there is also a data sheet available to the public (SN32F248_V2.0_EN.pdf), which should help progressing further. Initial information I gathered is that the chip is based on an ARM Cortex-M0.

Next steps

My next idea of progression is to try and set up the same tooling as someone developing hardware with this chip would. Get a C compiler and actually build a ROM of our own, to have a point of reference when starting reverse engineering. I do not have any experience looking at ARM code and not much experience with embedded software, so anything to aid my understanding in that area will be good.

Hopefully till next time,


Thanks to F for the proofread!

Leave a comment

Analyzing Torrent Repack Malware

12 Jul 2017

Never trust a repack…

The torrent I looked at was: The Legend of Zelda: Breath of the Wild CEMU 1.8.0b [Multi-Lang] by HZolomon.

TL;DR: It is definitely malware. All the torrent by HZolomon appear to have been infected with malware equal/similar to this one.

[MEGA Folder with relevant files] WARNING: THIS CONTAINS ACTIVE MALWARE (in case you didn’t read the title and like executing random files)… The key is 8NcPVw1TCm_dvZM9s2SU_g.


I used x64dbg, DbgChild, TitanHide, CFF Explorer, Exe2Aut and VirtualBox.

You have to select the checkboxes in the DbgChild plugin to automatically attach x64dbg to any process started by the executable you’re currently debugging:


From here on I’ll just give a brief description of each analysis step.



  • With innoextract (innounp has a similar error):
Stream error while parsing setup headers!
 ├─ detected setup version: 5.4.2
 └─ error reason: basic_ios::clear
If you are sure the setup file is not corrupted, consider
filing a bug report at
Done with 1 error.
  • Extracts %temp%\is-[A-Z0-9]{5}.tmp\setup.tmp (is-K35T2.tmp in MEGA folder)

  • Probably this is: and/or



Command line (this is similar to what InnoSetup does from what I know):

"C:\Users\Admin\AppData\Local\Temp\is-RPR25.tmp\setup.tmp" /SL5="$230522,1892858,54272,F:\Users\Admin\Documents\Downloads\The Legend of Zelda - Breath of the Wild\setup.exe" 
  • Extracts %temp%\is-[A-Z0-9]{5}.tmp\ISDone.dll and some other files (including unarc.dll).

  • Put a DLL breakpoint on unarc.dll in x64dbg.

  • Start the installation, which causes more stuff to be extracted to %temp%\is-[A-Z0-9]{5}.tmp.

All the extracted files are hidden. You can use attrib -S -H to unhide them (Windows explorer doesn’t allow you to do uncheck the Hidden box for some readon).

  • Break on FreeArcExtract (see my earlier blog post for more details). TL;DR it runs unarc.exe with the function arguments as command line arguments.

Some of the commands used in FreeArcExtract:

l -- setup-2.bin
x -o+ -pawdawdawd -wF:\BotW\ -dpF:\BotW\ -- setup-2.bin
  • Find cbArcExtract at ISDone.dll:$1A340 from the first parameter of FreeArcExtract, break on the password? action check:

password check

Arc password: awdawdawd

The unarc.dll uses compression algorithm hooks from facompress.dll (relevant code) + hooks for CLS-compressors (relevant code, CLS-MSC.dll, CLS-srep.dll) so make sure to put those next to unarc.exe if you want to (safely) extract the files.

  • After all the files are extracted it runs DSETUP.exe, which at first looked fine, but looking a second time the file is not signed by Microsoft and it has no version information or anything.



This is an AutoIt executable (32 bit), it’s basically the first layer of the dropper. With Exe2Aut I extracted the script (slightly deobfuscated by hand):

dropper layer 1

It tries to identify your anti-virus and based on that drops CLDe2bugLog.txt in your temp directory with the FileInstall function. It then replaces the bytes 00000000001C0004 with 377ABCAF271C0004 (7z header) and extracts it with the following command:

CLDe2bugLog.txt e -p"DQMDDMNBQ3824Nnd2nd8812@2*$(#!&NDQB2" CRDebugLog.txt

The contents of CRDebugLog.txt, but the malware inside does pretty much the same thing. I (unfortunately) looked at the contents of dxdllreg_x86:



attrib -h -r -s /S /D %userprofile%\AppData\Roaming\Microsoft\Windows\\svchost.exe
copy /y "64.exe" "%userprofile%\AppData\Roaming\Microsoft\Windows\svchost.exe"
attrib +h +r +s /S /D %userprofile%\AppData\Roaming\Microsoft\Windows\\svchost.exe
schtasks.exe /Create /XML "SystemCheck.xml" /TN "System\SystemCheck"
del 64.exe /f
del SystemCheck.xml /f
del CRDebugLog.txt /f
del CLDebugLog.txt /f
del "%0"

This copies the file to %userprofile%\AppData\Roaming\Microsoft\Windows\svchost.exe, which made it clear that this is indeed a malicious file. It then goes on to create a scheduled task with SystemCheck.xml.



This executes the newly-created svchost.exe with the -WindowsCheck command line every X amount of time (probably days, not really worth exploring in this case).

64.exe (svchost.exe)


This file is packed with Enigma x64. TitanHide works fine for debugging Enigma (ScyllaHide has issues). The original entry point (OEP) is at 64.exe:$3059C . It has stolen bytes, but they are easy to retrieve:

48 83 EC 28 E8 BF B3 00 00 48 83 C4 28 E9 36 FE FF FF

EDIT: I have been asked on reddit to give more details about the “stolen bytes” mentioned here. Before I could answer user izizizizizizi gave a nice explanation:

“Stolen bytes” (is there any non-colloquial name for this I wonder) is a feature of many packers/protectors which prevents easy dumping. During the protection process, a part of the original executable code gets removed and stored in the protector stub. When it’s about to be executed there’s a redirection to the protector’s code instead of the original function. The stub either writes original code in some dynamic buffer and executes it or an obfuscated version of the original function is executed.

To get them I created my own Hello World-style AutoIt executable and pasted the entry point.

After the ‘unpacking’ enigma, I extracted the SCRIPT resource and put it in a Hello World AutoIt executable (32 bit), I then used Exe2Aut.exe to get the AutoIt script source code (irrelevant parts omitted):


The interesting part is the bot() function:

stage2 C2

It uses a YouTube video (reported, but please report again) as a command and control mechanism. If the description contains one of the _download, _run, etc. command it will perform certain actions based on the data in the description (such as downloading a file or updating to a newer version).

It also appears to run some kind of crypto currency miner, although I couldn’t find the SystemCheck executable:


Well, that has been all for today. It has certainly been fun reversing malware for a change!

“Heb ik dat nou al gezouten?”

Leave a comment