neptools

Modding tools to Neptunia games
git clone https://git.neptards.moe/neptards/neptools.git
Log | Files | Refs | Submodules | README | LICENSE

launcher.c (3377B)


      1 #define WIN32_LEAN_AND_MEAN
      2 #include <windows.h>
      3 #include <shellapi.h>
      4 
      5 
      6 #define MSVC_URL "https://www.microsoft.com/en-us/download/details.aspx?id=40784"
      7 
      8 // set shit that's possible here
      9 #pragma comment(linker, "/merge:.text=.data")
     10 #pragma comment(linker, "/merge:.rdata=.data")
     11 
     12 static void strwcpy(wchar_t* dst, const wchar_t* src)
     13 {
     14   while (*dst++ = *src++);
     15 }
     16 
     17 void* memset(void* dst, int c, size_t len)
     18 {
     19   for (size_t i = 0; i < len; ++i)
     20     ((char *) dst)[i] = c;
     21   return dst;
     22 }
     23 
     24 static size_t strwlen(const wchar_t* ptr)
     25 {
     26   const wchar_t* p = ptr;
     27   while (*p++);
     28   return p - ptr;
     29 }
     30 
     31 static int inject_dll(HANDLE proc, wchar_t* fname)
     32 {
     33   size_t bytes = sizeof(wchar_t) * (strwlen(fname)+1);
     34   void* ptr = VirtualAllocEx(proc, NULL, bytes, MEM_COMMIT, PAGE_READWRITE);
     35   if (!ptr) return 0;
     36 
     37   if (!WriteProcessMemory(proc, ptr, fname, bytes, NULL)) return 0;
     38 
     39   HANDLE th = CreateRemoteThread(
     40     proc, NULL, 0, (LPTHREAD_START_ROUTINE) &LoadLibraryW, ptr, 0, NULL);
     41   if (!th) return 0;
     42 
     43   WaitForSingleObject(th, INFINITE);
     44   DWORD ret;
     45   if (!GetExitCodeThread(th, &ret) || ret == 0) return 0;
     46   CloseHandle(th);
     47 
     48   if (!VirtualFreeEx(proc, ptr, 0, MEM_RELEASE)) return 0;
     49 
     50   return 1;
     51 }
     52 
     53 static int mymain(void)
     54 {
     55   HANDLE h = LoadLibraryExA("msvcp120.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
     56   if (h == NULL)
     57   {
     58     int ret = MessageBoxA(
     59       NULL, "Please install MSVC 2013 runtime\n\nOpen download page?",
     60       NULL, MB_YESNO | MB_ICONERROR);
     61     if (ret == IDYES)
     62       ShellExecuteA(NULL, NULL, MSVC_URL, NULL, NULL, SW_SHOWNORMAL);
     63     return 1;
     64   }
     65   CloseHandle(h);
     66 
     67 #define BUF_SIZE 4096
     68   wchar_t buf[BUF_SIZE];
     69   GetModuleFileNameW(NULL, buf, BUF_SIZE);
     70   buf[BUF_SIZE-1] = 0; // maybe xp
     71 
     72   wchar_t* last_slash = buf;
     73   for (wchar_t* ptr = buf; *ptr; ++ptr)
     74     if (*ptr == L'\\')
     75       last_slash = ptr;
     76 
     77   if (*last_slash != L'\\' || last_slash - buf > BUF_SIZE - 22)
     78   {
     79     MessageBoxA(NULL, "Wrong module path", NULL, MB_OK | MB_ICONERROR);
     80     return 2;
     81   }
     82   strwcpy(last_slash + 1, L"NeptuniaReBirth3.exe");
     83 
     84   for (int i = '3';; --i)
     85   {
     86     last_slash[16] = i;
     87     unsigned attrib = GetFileAttributesW(buf);
     88     if (attrib != INVALID_FILE_ATTRIBUTES &&
     89         !(attrib & FILE_ATTRIBUTE_ENCRYPTED))
     90       break;
     91 
     92     if (i == '1')
     93     {
     94       strwcpy(&last_slash[9], L"VII.exe");
     95       unsigned attrib = GetFileAttributesW(buf);
     96       if (attrib != INVALID_FILE_ATTRIBUTES &&
     97           !(attrib & FILE_ATTRIBUTE_ENCRYPTED))
     98         break;
     99 
    100       MessageBoxA(NULL, "Couldn't find Neptunia",
    101                   NULL, MB_OK | MB_ICONERROR);
    102       return 2;
    103     }
    104   }
    105 
    106   STARTUPINFOW si;
    107   PROCESS_INFORMATION pi;
    108   memset(&si, 0, sizeof(si));
    109   memset(&pi, 0, sizeof(pi));
    110   si.cb = sizeof(STARTUPINFO);
    111   if (CreateProcessW(buf, GetCommandLineW(), NULL, NULL, FALSE,
    112                      CREATE_SUSPENDED, NULL, NULL, &si, &pi) == 0)
    113   {
    114     MessageBoxA(NULL, "Failed to start game", NULL, MB_OK | MB_ICONERROR);
    115     return 2;
    116   }
    117 
    118   strwcpy(last_slash + 1, L"neptools-server.dll");
    119   if (!inject_dll(pi.hProcess, buf))
    120   {
    121     TerminateProcess(pi.hProcess, 0);
    122     MessageBoxA(NULL, "DLL injection failed", NULL, MB_OK | MB_ICONERROR);
    123     return 3;
    124   }
    125 
    126   ResumeThread(pi.hThread);
    127   CloseHandle(pi.hProcess);
    128   CloseHandle(pi.hThread);
    129   return 0;
    130 }
    131 
    132 void __cdecl start(void);
    133 void __cdecl start(void)
    134 {
    135   ExitProcess(mymain());
    136 }