Skip to Main Content
All Trimarc services are now delivered through TrustedSec! Learn more
October 28, 2025

Hack-cessibility: When DLL Hijacks Meet Windows Helpers

Written by Oddvar Moe
Threat Hunting Penetration Testing

In preparation for a talk, Jason Lang (@curi0usJack) and I were doing at MCTTP about mining TTPs from VX-underground, we both ended up doing research based on ideas we got from reading all the different reports. For me, it started while reading about the various persistence techniques that are described in the various papers. One technique that caught my eye was the reference to Narrator.exe loading the MSTTSLocEnUS.dll upon execution. Having played a lot with Narrator in the past, I decided to take a closer look if this was still a thing or not. The techniques shown in this post requires local administrator access to the system you are manipulating.

I found references to this technique from the almighty @Hexacorn going back all the way to 2013 (Wow). My mind thought that this must surely be fixed now since this was such a long time ago, well let’s explore this rabbit hole together.

First, I needed to verify if this was still the case or not, so I ran Narrator while having a procmon running at the same time. This revealed something interesting.

It still looks for a variant of the dll in a different path? That is strange. Instead of the old path of %windir%\system32\speech\engine\tts\msttslocenus.dll it now looks for %windir%\system32\speech_onecore\engines\tts\msttsloc_onecoreenus.dll. Of course, this made me wonder if I could create a dll, place it there, and get it executed or not. Turns out, that works great. Interestingly, you do not need to create a dll with exports or anything like that. It just executes whatever you have in the attach statement of the dll.

The only issue is when the dll is executed, the Narrator continues, so you will get the voice telling you everything you click on and that is not particularly useful in an attack scenario. I decided to brainstorm for a while and found out that I could write code inside the dll that would identify the main thread and simply suspend that while continuing executing the thread that my dll code was in. After some trying and failing, I ended up creating this code that worked perfectly for what I had envisioned.

The flow now goes like this: You plant the dll and start the Narrator.exe, then the dll freezes the main program so that it does not start to use voice or highlight areas you click and executes the code in the dll planted. Having worked with the Narrator and other accessibility features in the past my brain reminded me of a thing while I was sleeping…

Persistence as User

Turns out that you can create a reg_sz named configuration under HKCU\Software\Microsoft\Windows NOT\CurrentVersion\Accessibility and set the accessibility option you want to start as the value. The screenshot below shows how to auto start Narrator and cursorindicator at logon.

In order to establish persistence, you can plant the malicious msttsloc_onecoreenus.dll, then set configuration to Narrator and you are all set. A logoff and logon confirmed this in my lab as shown in the video clip below.

Persistence as System

Another cool thing is that if you want to establish persistence as SYSTEM, you can do that as well. You only need to set the same value as described above under the HKLM hive instead of the HKCU. Example is shown in the screenshot below.

Setting the Narrator here will make sure that the Narrator starts when the login screen appears and it gets executed as SYSTEM.

Lateral Movement

To make this even better, you can also trigger this remotely in some scenarios and use it as lateral movement. This, however, requires you to have the permission to change the RDP settings remotely using the regedit. As before, you transfer the malicious msttsloc_onecoreenus.dll and instead of setting the Narrator in the configuration value to make it auto start, you are going to navigate to HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp and change the SecurityLayer to 0.

To trigger the execution, you simply RDP to the host you are targeting and then when you see the login page you press CTRL+WIN+ENTER to trigger the start of the Narrator and get your code executed. The code will stop as soon as you close the RDP, so your code needs to move into another process or similar, which is an exercise I will leave up to you.

Bring Your Own Accessibility

Another interesting thing I found is that you can simply create your own accessibility option (or ATs as they are called in the registry) and configure it to run in the configuration setting as mentioned earlier in this post. How do you do that? In my lab, I simply exported the CursorIndicator and opened it up in Notepad to adjust the name and description. After saving that, I imported it into the registry.

After the import, I navigated to the new ATs and changed the binary path as shown in the screenshot below.

Next, you need to place the payload you want to execute in the c:\temp\crutch.exe location. If you are going to do this remotely, you will need to either use the connect to network registry and add the keys/values or manually add them using Impacket’s reg.py something similar. After you have created your own ATs, you can add the name directly in the configuration, either in HKLM or HKCU, and it will run upon next boot/logon. To spice things up you can also specify an unc path instead of the local file system, meaning you could host the file on a network share if you wanted.

Outro

When writing this blog post and doing some additional Google searches, I ended up finding a blog post by Adam aka @Hexacorn about some of the same research in regards to the persistence.

He also mentions a way to start the ATs that is pretty cool and is done by running ATBroker.exe /start . So, in our example when we introduced our own it would be ATBroker.exe /start Crutch. These techniques have been tested on the latest version of Windows 10 and 11 as of the release of this blogpost.

Hope you found this post interesting and learned something new.