You could create a loader which simply creates your target app in suspended state and loads dll into virtual address space of that process. That way the dll you injected would run before entrypoint of the target app.
Example code:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
LPCSTR dllname = "testdll.dll";
LPVOID stringAddr = NULL;
LPVOID LoadLib = NULL;
LoadLib = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (LoadLib == NULL) {
return -1;
}
if (!CreateProcess(TEXT("target.exe"), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
return -1;
}
stringAddr = VirtualAllocEx(pi.hProcess, NULL, strlen(dllname), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (stringAddr == NULL) {
return -1;
}
WriteProcessMemory(pi.hProcess, stringAddr, dllname, strlen(dllname), NULL);
CreateRemoteThread(pi.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLib, stringAddr, NULL, NULL);
ResumeThread(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;