Skip to content

Instantly share code, notes, and snippets.

@DanielGibson
Last active January 31, 2024 17:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DanielGibson/f4ea4d46fc279d64a2d35a326e7a1a88 to your computer and use it in GitHub Desktop.
Save DanielGibson/f4ea4d46fc279d64a2d35a326e7a1a88 to your computer and use it in GitHub Desktop.
ULTRA-SOPHISTICATED 0DAY APT SUPERMALWARE PROXY EXE

Inspired by our understanding of what CVE-2024-23940 does (see https://medium.com/@s1kr10s/av-when-a-friend-becomes-an-enemy-55f41aba42b1) HORST, the 1337est of hackers, infamous for having hacked THE DIALER back in 1998, has developed the next generation of that attack, and kindly gave me permission to demonstrate it here!

It turns out that you can't just write Proxy-DLLs that pass on function calls to original DLLs and also do evil things, but you can also create a Proxy Executable that calls the original exe and also does evil things!

Usage

  1. Compile proxyexe.c to get ANTIVIRUS.EXE
  2. Rename the original ANTIVIRUS.EXE from Serious Snakeoil Co(R) Super Antivirus(TM) to ANTIVIRUS-ORIG.EXE
  3. Move ANTIVIRUS.EXE to the installation folder of Serious Snakeoil Co(R) Super Antivirus(TM), next to ANTIVIRUS-ORIG.EXE
  4. Reboot
  5. Congratulations, you have hacked your system!
  6. ???
  7. $$$ PROFIT $$$ !

Proof of Concept Video

Hack.mp4
/*
* Just a trivial stupid wrapper quake2.exe that starts yquake2.exe^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H
*
* I mean, ULTRA-SOPHISTICATED 0DAY APT SUPERMALWARE PROXY EXE THAT STARTS
* THE ORIGINAL ANTIVIRUS EXECUTABLE SO THE USER CAN'T TELL THAT THIS
* ISN'T WHAT THEY THINK IT IS!!1
*
* It calls it with the whole path (assuming it's in same directory as this wrapper)
* and passes the commandline
*
* This should allow us to rename the real executable to yquake2.exe (to hopefully
* avoid trouble with whatever stupid thing interferes with mouse input once
* console has been opened if the games executable is called quake2.exe)
* while avoiding confusion for people upgrading their yq2 installation who still have
* shortcuts (possibly in Steam) to quake2.exe that would otherwise launch an old version.
*
* Can be built with just
* $ gcc -Wall -o quake2.exe wrapper.c
* in our mingw build environment, will only depend on kernel32.dll and MSVCRT.DLL then,
* which should be available on every Windows installation.
*
* (C) 2017 Daniel Gibson
* License:
* This software is dual-licensed to the public domain and under the following
* license: you are granted a perpetual, irrevocable license to copy, modify,
* publish, and distribute this file as you see fit.
* No warranty implied; use at your own risk.
*
* So you can do whatever you want with this code, including copying it
* (or parts of it) into your own source.
*/
#include <windows.h>
#include <wchar.h>
#include <stdio.h>
static const WCHAR WRAPPED_EXE[] = L"ANTIVIRUS-ORIG.exe";
// the struct and OnGetWindowByProcess taken from https://stackoverflow.com/a/17166455
typedef struct {
DWORD pid;
HWND hwnd;
} WINDOWPROCESSINFO;
static BOOL CALLBACK OnGetWindowByProcess(HWND hwnd, LPARAM lParam)
{
WINDOWPROCESSINFO *infoPtr = (WINDOWPROCESSINFO *)lParam;
DWORD check = 0;
BOOL br = TRUE;
GetWindowThreadProcessId(hwnd, &check);
if (check == infoPtr->pid)
{
infoPtr->hwnd = hwnd;
br = FALSE;
}
return br;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WCHAR* cmdLine = GetCommandLineW();
WCHAR exePath[2048];
WCHAR* lastBackSlash = exePath;
int maxLenSafe = sizeof(exePath)/sizeof(WCHAR) - wcslen(WRAPPED_EXE);
// get full path to this executable..
DWORD len = GetModuleFileNameW(NULL, exePath, maxLenSafe);
if(len <= 0 || len == maxLenSafe) {
// an error occured, clear exe path
exePath[0] = 0;
} else {
// .. cut off executable name (after last backslash in path)
lastBackSlash = wcsrchr(exePath, L'\\');
if(lastBackSlash != NULL) {
lastBackSlash[1] = 0;
} else {
// if there was no backslash, fall back to using only the wrapped exe name
// (appended to empty exePath buffer)
lastBackSlash = exePath;
lastBackSlash[0] = 0;
}
}
// .. append wrapped executable name to path ..
// should be safe, because maxLenSafe subtracted WRAPPED_EXE's length
// (and that's very conservative, we removed the original .exe name after all)
wcscat(lastBackSlash, WRAPPED_EXE);
// .. and start the wrapped executable
{
STARTUPINFOW si = {0};
PROCESS_INFORMATION pi = {0};
BOOL ret = FALSE;
si.cb = sizeof(si);
ret = CreateProcessW(exePath, cmdLine,
NULL, // process security attributes
NULL, // thread security attributes
FALSE, // don't inherit handles
0, // no creation flag
NULL, // environment block - no changes, use ours
NULL, // don't change CWD
&si, &pi);
// hackhack - TODO: EVIL THINGS GO HERE
MessageBox(NULL, "Pwned by HORST, the 1337est of h4x0rz!",
"You have been pwned!",
MB_HELP|MB_ICONWARNING|MB_TOPMOST);
if(!ret)
{
fprintf(stderr, "Couldn't CreateProcess() (%ld).\n", GetLastError());
return 1;
}
Sleep(1000); // wait until ANTIVIRUS should have created its window
// send ANTIVIRUS window to foreground, as shown in https://stackoverflow.com/a/17166455
// first we need to get its HWND
WINDOWPROCESSINFO info;
info.pid = GetProcessId(pi.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
// wait for wrapped exe to exit
WaitForSingleObject(pi.hProcess, INFINITE);
// close the process and thread object handles
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
return 0;
}
@DanielGibson
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment