Skip to content

Instantly share code, notes, and snippets.

@juntalis
Created October 5, 2014 03:49
Show Gist options
  • Save juntalis/62400b02ba1862dab0f7 to your computer and use it in GitHub Desktop.
Save juntalis/62400b02ba1862dab0f7 to your computer and use it in GitHub Desktop.
Executable wrapper for allowing only a single instance of a program to run, using a configurable number of args for the identity.
// Preconfigure
#define _UNICODE 1
#define _CONSOLE 1
#include <pch.h>
#include <crc16.h>
struct exe_args_t
{
HANDLE hMutex;
size_t szExecutable;
tchar* lpExecutable;
int iArgsCount;
tchar** lpArgs;
# ifdef _DEBUG
tchar* lpMutexKey;
# endif
};
static tchar* stprintf_alloc(tchar* message, ...);
static tchar* vstprintf_alloc(tchar* message, va_list args);
static noret fatal_message(u32 dwError, tchar* sPrefix, tchar* sCode, bool blDealloc)
{
# ifdef WITH_MSGBOX
tchar* lpDisplayBuf = stprintf_alloc(_T("%s: FATAL:%s"), sPrefix, sCode);
MessageBox(NULL, (const tchar*)lpDisplayBuf, _T("Fatal Error"), MB_OK | MB_ICONERROR);
xfree(lpDisplayBuf);
# else
_tprintf(_T("%s: FATAL:%s\n"), sPrefix, sCode);
# endif
if(blDealloc) xfree(sCode);
ExitProcess(dwError);
}
static void show_message(tchar* message, ...)
{
va_list args = NULL;
tchar* lpMessage = NULL;
// Allocate buffer for our resulting format string.
va_start(args, message);
lpMessage = vstprintf_alloc(message, args);
va_end(args);
# ifdef WITH_MSGBOX
MessageBox(NULL, (const tchar*)lpMessage, _T("Single Instance App"), MB_OK | MB_ICONINFORMATION);
# else
_tprintf(_T("%s\n"), lpMessage);
# endif
xfree(lpMessage);
}
#define check_not_code(ERRCODE,CODE) \
if(CODE) \
fatal_message(ERRCODE, _T("[") __TFILE__ _T(":") XSTR(__LINE__) _T("]"), XSTR(CODE), false)
#define check_code(ERRCODE,CODE) check_not_code(ERRCODE, !(CODE))
#define xcheckn(CODE) check_not_code(1, CODE)
#define xcheck(CODE) check_code(1, CODE)
static inline void* xalloc(size_t szBuf)
{
void* p = NULL;
xcheck(p = malloc(szBuf));
memset(p, 0, szBuf);
return p;
}
#define typalloc(TYPE) ((TYPE*)xalloc(sizeof(TYPE)))
#define aalloc(TYPE,COUNT) ((TYPE*)xalloc(((size_t)COUNT) * sizeof(TYPE)))
#define salloc(TYPE,COUNT) aalloc(TYPE,(COUNT+1))
#define tcsalloc(COUNT) salloc(tchar,COUNT)
#define xfatalme(ERRCODE,MSG,DEALLOC) fatal_message(ERRCODE, _T("[") __TFILE__ _T(":") XSTR(__LINE__) _T("]"), MSG, DEALLOC)
// Only used once or twice, thus the inline
static tchar* vstprintf_alloc(tchar* message, va_list args)
{
tchar *lpResult;
size_t szDisplayBuf;
// Check the resulting size of the buffer.
szDisplayBuf = (size_t)_vsctprintf((const tchar*)message, args) + 1;
// Allocate our buffer.
if(!(lpResult = (tchar*)calloc(szDisplayBuf, sizeof(tchar)))) {
return NULL;
}
// Finally, fill in the message.
_vsntprintf(lpResult, szDisplayBuf, (const tchar*)message, args);
return lpResult;
}
// Only used once or twice, thus the inline
static tchar* stprintf_alloc(tchar* message, ...)
{
va_list args = NULL;
tchar* lpResult = NULL;
// Allocate buffer for our resulting format string.
va_start(args, message);
lpResult = vstprintf_alloc(message, args);
va_end(args);
return lpResult;
}
static tchar* tcstrim(tchar *str)
{
tchar *start = str;
// Immediately return if null arg.
if(IS_BAD_STR(str)) return str;
// Trim leading space
while(_istspace(*start)) start++;
// All spaces.
if(*start == _T('\0')) {
memset((void*)str, 0, (size_t)(x2ptr(start) - x2ptr(str)));
start = str;
} else {
tchar* pos,
*end = (pos = (tchar*)(start + _tcslen((const tchar*)start) - 1));
while(pos > start && _istspace(*pos)) pos--;
memset((void*)++pos, 0, end - pos);
}
return start;
}
// Only called from one function, thus the inline.
// Most likely going to be removed.
static inline noret error_in_error_message(u32 dwErr, u32 dwErrErr, tchar* sPrefix, tchar* sMessage, va_list args)
{
tchar* sErrMsg = NULL, *sErrFinal = NULL;
sErrMsg = vstprintf_alloc(sMessage, args);
sErrFinal = stprintf_alloc(
_T("Error Code 0x%08X occurred while trying to print info about another error: [0x%08X] %s"),
dwErrErr,
dwErr,
sErrMsg
);
xfree(sErrMsg);
fatal_message(dwErrErr, sPrefix, sErrFinal, true);
}
#define xerror(...) error_message(ERROR_SUCCESS, __VA_ARGS__)
#define xerrorn(ERRCODE,...) error_message(ERRCODE, __VA_ARGS__)
#define xerrorfn(FN) error_message(ERROR_SUCCESS, XSTR(FN) _T("() failed."))
#define xfatal(...) { \
error_message(ERROR_SUCCESS, __VA_ARGS__); \
ExitProcess(1); \
}
#define xfataln(ERRCODE,...) { \
error_message(ERRCODE, __VA_ARGS__); \
ExitProcess(ERRCODE); \
}
#define xfatalfn(FN) { \
error_message(ERROR_SUCCESS, XSTR(FN) _T("() failed.")); \
ExitProcess(1); \
}
static void error_message(u32 dwErr, tchar* sMessage, ...)
{
tchar *lpDisplayBuf = NULL;
u32 dwErrErr = ERROR_SUCCESS;
va_list vlArgs = NULL;
va_start(vlArgs, sMessage);
lpDisplayBuf = vstprintf_alloc(sMessage, vlArgs);
va_end(vlArgs);
if(dwErr == ERROR_SUCCESS) dwErr = GetLastError();
if(dwErr != ERROR_SUCCESS) {
tchar *lpErrMsg = NULL, *lpTemp = NULL;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (tchar*)&lpErrMsg, 0, NULL
);
lpTemp = stprintf_alloc(_T("%s - Windows Error [0x%08X]: %s"), lpDisplayBuf, dwErr, lpErrMsg);
xfree(lpDisplayBuf);
lpDisplayBuf = lpTemp;
LocalFree((HLOCAL)lpErrMsg);
}
# ifdef WITH_MSGBOX
MessageBox(NULL, (const tchar*)lpDisplayBuf, _T("Windows Error"), MB_OK | MB_ICONERROR);
# else
_tprintf(_T("FATAL: %s\n"), lpDisplayBuf);
# endif
xfree(lpDisplayBuf);
}
#ifndef GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
# define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 0x00000002
#endif
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
# define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 0x00000004
#endif
static HMODULE GetModuleNoRefEx(const tchar* sName, u32 dwFlags)
{
HMODULE hMod = NULL;
if(!(dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
dwFlags |= GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
return GetModuleHandleEx(dwFlags, sName, &hMod) ? hMod : NULL;
}
static HMODULE GetModuleNoRef(const tchar* sName)
{
return GetModuleNoRefEx(sName, 0);
}
#ifdef BUILD_ARCH_X86
static bool is_wow64(void)
{
__asm
{
mov ax, cs
shr eax, 5
}
}
static int without_wow64_redirection(int(__cdecl* lpExecFunc)(void*), void* userdata)
{
int r;
if(!is_wow64()) {
r = lpExecFunc(userdata);
} else {
PVOID lpRevert = NULL;
HMODULE hKernel32 = NULL;
BOOL (WINAPI* lpDisableWow64FsRedirection)(PVOID*);
BOOL (WINAPI *lpRevertWow64FsRedirection)(PVOID);
check_code(1, hKernel32 = GetModuleNoRef(_T("kernel32.dll")));
*((FARPROC*)&lpDisableWow64FsRedirection) = GetProcAddress(hKernel32, "Wow64DisableWow64FsRedirection");
*((FARPROC*)&lpRevertWow64FsRedirection) = GetProcAddress(hKernel32, "Wow64RevertWow64FsRedirection");
if(!lpDisableWow64FsRedirection || !lpRevertWow64FsRedirection) {
xfatalfn(GetProcAddress);
}
if(!lpDisableWow64FsRedirection(&lpRevert)) {
xfatalfn(Wow64DisableWow64FsRedirection);
}
r = lpExecFunc(userdata);
lpRevertWow64FsRedirection(lpRevert);
}
return r;
}
#else
static int without_wow64_redirection(int(__cdecl* lpExecFunc)(void*), void* userdata)
{
return lpExecFunc(userdata);
}
#endif
/** String Duplication */
static tchar* xtcsndup(tchar* s, size_t size)
{
tchar* p;
size_t szlen;
if (!s) { return NULL; }
if ((szlen = _tcslen((const tchar*)s)) < size) size = szlen;
p = tcsalloc(size);
memcpy((void*)p, (const void*)s, size * sizeof(tchar));
return p;
}
/** Check if arg contains a space */
static bool hasspace(tchar* arg, size_t szLen)
{
size_t i = 0;
for(; i < szLen; i++)
if(_istspace(arg[i]))
return true;
return false;
}
#if 0
/** Quote if necessary */
static tchar* quotearg(tchar* arg, size_t* szArgLen)
{
tchar* result = NULL;
// Check for EMPTY args. If found, don't both adding quotes.
if(!arg || !(*szArgLen = _tcslen(arg))) {
return tcsalloc(0);
}
if(!hasspace(arg, *szArgLen)) {
return _tcsdup(arg);
}
*szArgLen += 2;
result = tcsalloc(szArgLen);
// Now set result to the value of arg, with surrounding quotes.
if(!(_sntprintf(result, szArgLen, _T("\"%s\""), arg))) {
xerror(_T("Failed quoting arguments!"));
}
return result;
}
#endif
#ifdef _DEBUG
static inline tchar* quote(tchar* arg, size_t szLen)
{
tchar* sBuf = tcsalloc(szLen + 2);
_stprintf(sBuf, _T("\"%s\""), arg);
return sBuf;
}
/** Fake execution */
static int execute_args_wait(void* lpData)
{
int i = 0;
struct exe_args_t* lpLaunchArgs = (struct exe_args_t*)lpData;
_tprintf(_T("Mutex Key: %s\n"), lpLaunchArgs->lpMutexKey);
_tprintf(_T("Command Line:\n"));
_tprintf(_T(" [%d] => %s\n"), 0, lpLaunchArgs->lpExecutable);
if(!lpLaunchArgs->iArgsCount) { return 0; }
for(; i < lpLaunchArgs->iArgsCount; i++) {
size_t szLen;
tchar* arg = lpLaunchArgs->lpArgs[i];
if(szLen = _tcslen(arg)) {
if(hasspace(arg, szLen)) {
arg = quote(lpLaunchArgs->lpArgs[i], szLen);
szLen = (size_t)-1;
}
}
_tprintf(_T(" [%d] => %s\n"), i+1, arg);
if(szLen == (size_t)-1) {
xfree(arg);
}
}
return 0;
}
#else
// Caller responsible for cleanup.
static tchar* build_cmdline(struct exe_args_t* lpLaunchArgs)
{
int i = 0;
tchar *sCmdLine = NULL;
size_t szCmdLine = 0;
bool* lpblNeedsSpaces = aalloc(bool, lpLaunchArgs->iArgsCount + 1);
lpblNeedsSpaces[0] = hasspace(lpLaunchArgs->lpExecutable, lpLaunchArgs->szExecutable);
szCmdLine = *lpblNeedsSpaces ? lpLaunchArgs->szExecutable + 3 : lpLaunchArgs->szExecutable + 1;
for(; i < lpLaunchArgs->iArgsCount; i++) {
size_t szLen;
//tchar* argvTrimmed = tcstrim(argv[i]);
szLen = _tcslen(lpLaunchArgs->lpArgs[i]);
if(!szLen) continue;
if(lpblNeedsSpaces[i+1] = hasspace(lpLaunchArgs->lpArgs[i], szLen)) {
szCmdLine += szLen + 3;
} else {
szCmdLine += szLen + 1;
}
}
// There's an unnecessary space accounted for.
sCmdLine = tcsalloc(--szCmdLine);
if(*lpblNeedsSpaces) {
_stprintf(sCmdLine, _T("\"%s\""), lpLaunchArgs->lpExecutable);
} else {
_tcscpy(sCmdLine, lpLaunchArgs->lpExecutable);
}
for(i = 0; i < lpLaunchArgs->iArgsCount; i++) {
if(lpblNeedsSpaces[i+1]) {
_tcscat(sCmdLine, _T(" \""));
_tcscat(sCmdLine, lpLaunchArgs->lpArgs[i]);
_tcscat(sCmdLine, _T("\""));
} else {
_tcscat(sCmdLine, _T(" "));
_tcscat(sCmdLine, lpLaunchArgs->lpArgs[i]);
}
}
xfree(lpblNeedsSpaces);
return sCmdLine;
}
static LPPROCESS_INFORMATION execute_process(tchar* sCmdLine)
{
STARTUPINFO si;
LPPROCESS_INFORMATION ppi = typalloc(PROCESS_INFORMATION);
// Zero out structs and set sizes.
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
/* Program launching. */
if (!CreateProcess(
NULL, /* No module name (use command line) */
sCmdLine, /* Command line */
NULL, /* Process handle not inheritable */
NULL, /* Thread handle not inheritable */
FALSE, /* Set handle inheritance to FALSE */
0, /* No creation flags */
NULL, /* Use parent's environment block */
NULL, /* Use parent's starting directory */
&si, /* Pointer to STARTUPINFO structure */
ppi /* Pointer to PROCESS_INFORMATION structure */
)) {
xfree(ppi);
xfree(sCmdLine);
xfatalfn(CreateProcess);
ExitProcess(1);
}
//ResumeThread(ppi->hThread);
xfree(sCmdLine);
return ppi;
}
// Cleans up a call to execute_process.
static inline int cleanup_execute(LPPROCESS_INFORMATION ppi)
{
DWORD dwRes;
if(!GetExitCodeProcess(ppi->hProcess, &dwRes)) {
xfatalfn(GetExitCodeProcess);
}
MAYBE_CLOSE_HANDLE(ppi->hThread);
MAYBE_CLOSE_HANDLE(ppi->hProcess);
xfree(ppi);
return (int)dwRes;
}
static inline int execute_wait(tchar* sCmdLine)
{
LPPROCESS_INFORMATION ppi;
if(!(ppi = execute_process(sCmdLine))) return 1;
// Wait until the application actually finishes.
WaitForSingleObject(ppi->hProcess, INFINITE);
return cleanup_execute(ppi);
}
// Caller responsible for cleanup.
static int execute_args_wait(void* lpData)
{
int r;
struct exe_args_t* lpLaunchArgs = (struct exe_args_t*)lpData;
tchar *sCmdLine = build_cmdline(lpLaunchArgs);
r = execute_wait(sCmdLine);
return r;
}
#endif
/** Automatically allocate the necessary buffer, then return the result of SearchPath */
static tchar* alloc_search_path(tchar* exename, u32* lpszExecutable)
{
tchar* lpFilePart = NULL,
* lpPathBuffer = NULL;
if(!( *lpszExecutable = SearchPath(NULL, exename, _T(".exe"), 0, NULL, &lpFilePart) )) {
xfatalfn(SearchPath);
}
lpPathBuffer = aalloc(tchar, *lpszExecutable);
if(!( *lpszExecutable = SearchPath(NULL, exename, _T(".exe"), *lpszExecutable, lpPathBuffer, &lpFilePart) )) {
xfree(lpPathBuffer);
lpPathBuffer = NULL;
xfatalfn(SearchPath);
}
return lpPathBuffer;
}
#define READ_FLAGS_ATTRS FILE_ATTRIBUTE_NORMAL
#define DOS_SIGNATURE_SIZE RTL_FIELD_SIZE(IMAGE_DOS_HEADER, e_magic)
#define NT_SIGNATURE_SIZE RTL_FIELD_SIZE(IMAGE_NT_HEADERS32, Signature)
#define NT_HEADERS_ADDR_OFFSET FIELD_OFFSET(IMAGE_DOS_HEADER, e_lfanew)
#define OPTIONAL_HEADER_OFFSET FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)
#define CHECKSUM32_OFFSET FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32, CheckSum)
#define CHECKSUM64_OFFSET FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64, CheckSum)
static inline bool read_from_origin_offset(HANDLE hFile, s32 lOffset, void* lpBuffer, u32 dwBytesToRead, u32 dwOrigin)
{
u32 dwBytesRead = 0;
if(SetFilePointer(hFile, lOffset, NULL, dwOrigin) == INVALID_SET_FILE_POINTER) {
xerrorfn(SetFilePointer);
return false;
} else if(!ReadFile(hFile, lpBuffer, dwBytesToRead, &dwBytesRead, NULL)) {
xerror(_T("Failed to read %d bytes from PE file!"), dwBytesToRead);
return false;
}
return true;
}
static u32 pe_checksum(tchar* lpExePath)
{
// Yeah, I'm lazy.
#define read_offset_origin(OFFSET,RETVAR,ORIGIN) \
read_from_origin_offset(hFile, OFFSET, (void*)&(RETVAR), sizeof(RETVAR), ORIGIN)
#define read_at(OFFSET,RETVAR) \
read_offset_origin(OFFSET, RETVAR, FILE_BEGIN)
#define read_offset(OFFSET,RETVAR) \
read_offset_origin(OFFSET, RETVAR, FILE_CURRENT)
#define cleanup(MSG,...) \
CloseHandle(hFile); \
xfatal(MSG, __VA_ARGS__ )
HANDLE hFile;
s32 lOffset = 0;
u16 wTempStorage = 0;
u32 dwChecksum, dwNtHeaders, dwTempStorage = 0;
// First open our PE for reading.
if(IS_INVALID_HANDLE(
hFile = CreateFile(lpExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, READ_FLAGS_ATTRS, NULL)
)) {
xfatal(_T("Failed to open file: %s"), lpExePath);
// Read IMAGE_DOS_HEADER.e_magic
} else if(!ReadFile(hFile, (void*)&wTempStorage, sizeof(wTempStorage), &dwTempStorage, NULL) || (wTempStorage != IMAGE_DOS_SIGNATURE)) {
cleanup(_T("%s is not a valid PE file!"), lpExePath);
// Read the offset to our IMAGE_NT_HEADERS from IMAGE_DOS_HEADER.lfanew
} else if(
(!read_at(NT_HEADERS_ADDR_OFFSET, dwNtHeaders) || (dwNtHeaders <= NT_HEADERS_ADDR_OFFSET)) ||
(!read_at(dwNtHeaders, dwTempStorage) || (dwTempStorage != IMAGE_NT_SIGNATURE))
) {
cleanup(_T("No PE header found in file: %s [lOffset=0x%08X, dwTempStorage=0x%08X]"), lpExePath, lOffset, dwTempStorage);
// Read our IMAGE_OPTIONAL_HEADER.Magic to determine build architecture of our executable.
} else if(!read_offset(OPTIONAL_HEADER_OFFSET - sizeof(dwNtHeaders), wTempStorage)) {
cleanup(_T("Failed to read IMAGE_OPTIONAL_HEADER.Magic for PE: %s"), lpExePath);
}
if(wTempStorage == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
lOffset = CHECKSUM32_OFFSET;
} else if(wTempStorage == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
lOffset = CHECKSUM64_OFFSET;
} else {
cleanup(_T("Unrecognized value 0x%04X found for IMAGE_OPTIONAL_HEADER.Magic of PE: %s"), wTempStorage, lpExePath);
}
// Finally, read our image checksum.
if(!read_offset(lOffset, dwChecksum)) {
cleanup(_T("Failed to read checksum for PE: %s"), lpExePath);
}
CloseHandle(hFile);
return dwChecksum;
# undef cleanup
# undef read_offset
# undef read_at
# undef read_offset_origin
}
#ifdef _UNICODE
static u32 uCodePage = 0;
static inline int xwcstombs(const tchar* lpwBuffer, size_t szwBuffer, char* lpcBuffer, size_t szcBuffer)
{
return WideCharToMultiByte(uCodePage, 0, lpwBuffer, szwBuffer, lpcBuffer, szcBuffer, NULL, NULL);
}
#endif
#define MUTEX_KEY_BASE _T("singleinst.exec-")
#define MUTEX_KEY_BASE_LEN TLEN(MUTEX_KEY_BASE)
// TODO: Reuse the args lengths during launch instead of recalculating it.
static inline tchar* generate_mutex_key(u32 dwChecksum, int iArgIds, tchar* argv[])
{
int i = 0;
tchar* lpMutexKey = NULL, *lpCurrent;
size_t szMutexKey = MUTEX_KEY_BASE_LEN;
uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
// Includes trailing 0
szMutexKey = TLEN(MUTEX_KEY_BASE);
szMutexKey += 8 + (8 * iArgIds);
lpMutexKey = tcsalloc(szMutexKey);
_tcscpy(lpMutexKey, MUTEX_KEY_BASE);
_stprintf(lpMutexKey, MUTEX_KEY_BASE _T("%08X"), dwChecksum);
lpCurrent = lpMutexKey + MUTEX_KEY_BASE_LEN + 7;
for(; i < iArgIds; i++) {
crc_t crcArg;
char* lpcArg;
size_t szArg = _tcslen(argv[i]);
# ifdef _UNICODE
lpcArg = salloc(char, szArg);
xwcstombs((const tchar*)argv[i], -1, lpcArg, szArg * sizeof(char));
# else
lpcArg = argv[i];
# endif
crcArg = crc_init();
crcArg = crc_update(crcArg, (unsigned char *)lpcArg, szArg);
crcArg = crc_finalize(crcArg);
_stprintf(lpCurrent, _T("%08X"), crcArg);
lpCurrent += 8;
# ifdef _UNICODE
xfree(lpcArg);
# endif
}
return lpMutexKey;
}
#ifdef SUBSYSTEM_CONSOLE
int _tmain(int argc, tchar* argv[])
{
#else
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpOriginalCmdLine, int nCmdShow)
{
# define argc __argc
# define argv __targv
#endif
u32 dwChecksum;
tchar *lpMutexKey;
int r = 0, iArgIds, nargc;
struct exe_args_t* lpLaunchArgs = NULL;
if(argc < 3) {
show_message(_T("Usage: %s <number-of-identifying-args> <program> [arg1] [arg2] ... [argN]"), argv[0]);
return 0;
}
nargc = argc - 2;
if(!(iArgIds = _tstoi((const tchar*)argv[1]))) {
xfatal(_T("Failed to parse identifying arg count from value: %s"), argv[1]);
} else if(nargc < iArgIds) {
xfatal(_T("Expected at least %d arguments, but only found %d."), iArgIds, nargc);
}
// Locate the executable path and generate a checksum key using the following
// formula:
//
// MUTEX_KEY_BASE + hex(execute-pe-checksum) + crc
//
iArgIds--;
lpLaunchArgs = typalloc(struct exe_args_t);
lpLaunchArgs->lpExecutable = alloc_search_path(argv[2], &(lpLaunchArgs->szExecutable));
dwChecksum = pe_checksum(lpLaunchArgs->lpExecutable);
if(iArgIds > 0) {
lpMutexKey = generate_mutex_key(dwChecksum, iArgIds, &(argv[3]));
} else {
lpMutexKey = generate_mutex_key(dwChecksum, iArgIds, NULL);
}
if(IS_INVALID_HANDLE(lpLaunchArgs->hMutex = CreateMutex(NULL, TRUE, lpMutexKey))) {
xfree(lpMutexKey);
goto cleanup;
}
# ifdef _DEBUG
lpLaunchArgs->lpMutexKey = lpMutexKey;
# else
xfree(lpMutexKey);
# endif
lpLaunchArgs->iArgsCount = nargc - 1;
if(lpLaunchArgs->iArgsCount > 0) {
lpLaunchArgs->lpArgs = &(argv[3]);
} else {
lpLaunchArgs->lpArgs = NULL;
}
r = without_wow64_redirection(&execute_args_wait, (void*)lpLaunchArgs);
# ifdef _DEBUG
xfree(lpLaunchArgs->lpMutexKey);
# endif
cleanup:
MAYBE_CLOSE_MUTEX(lpLaunchArgs->hMutex);
xfree(lpLaunchArgs->lpExecutable);
xfree(lpLaunchArgs);
return r;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment