├── swtor_fix.exe ├── swtor_fix.png ├── .whitesource ├── README.md ├── swtor_fix.c └── launcher.sh /swtor_fix.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aljen/swtor_fix/HEAD/swtor_fix.exe -------------------------------------------------------------------------------- /swtor_fix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aljen/swtor_fix/HEAD/swtor_fix.png -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | ########################################################## 2 | #### WhiteSource Integration configuration file #### 3 | ########################################################## 4 | 5 | # Configuration # 6 | #---------------# 7 | ws.repo.scan=true 8 | vulnerable.check.run.conclusion.level=failure 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fix for Star Wars: The Old Republic to run on WINE 2 | ========= 3 | 4 | WINE doesn't handle SW:TOR by default and needs a patch (http://bugs.winehq.org/show_bug.cgi?id=29168) 5 | I wanted to use WINE from a repo without patching, so I implemented this small application to allow SW:TOR to work correctly. 6 | All it does is waiting for swtor.exe to start up, takes his PID and launch two threads. 7 | First thread simply waits for swtor.exe to end to do cleanup, the second one just updates KUSER_SHARED_DATA's time fields, so the game 8 | network code just works as it should be and then copies those into swtor.exe process memory. 9 | 10 | This code is based on original patch for WINE by Carsten Juttner & Xolotl Loki 11 | 12 | How to: 13 | - copy swtor_fix.exe to ~/.wine/drive_c 14 | - run two terminals 15 | - on first one, run: 16 | $ WINEDEBUG=-all wine c:\swtor_fix.exe 17 | - switch to second one and run: 18 | $ WINEDEBUG=-all wine ~/.wine/drive_c/Program\ Files\ \(x86\)/Electronic\ Arts/BioWare/Star\ Wars\ -\ The\ Old\ Republic/launcher.exe 19 | 20 | -------------------------------------------------------------------------------- /swtor_fix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef NTSTATUS (WINAPI *NTQUERYSYSTEMTIME)(PLARGE_INTEGER); 7 | typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS, 8 | PVOID, ULONG, PULONG); 9 | 10 | // KUSER_SHARED_DATA offsets, defined here to not inclue ddk.. 11 | #define ADDR_INTERRUPTTIME_HIGH2TIME 0x7FFE0010 12 | #define ADDR_INTERRUPTTIME_LOWPART 0x7FFE0008 13 | #define ADDR_INTERRUPTTIME_HIGH1TIME 0x7FFE000C 14 | #define ADDR_SYSTEMTIME_HIGH2TIME 0x7FFE001C 15 | #define ADDR_SYSTEMTIME_LOWPART 0x7FFE0014 16 | #define ADDR_SYSTEMTIME_HIGH1TIME 0x7FFE0018 17 | #define ADDR_TICKCOUNT_HIGH2TIME 0x7FFE0328 18 | #define ADDR_TICKCOUNT_LOWPART 0x7FFE0320 19 | #define ADDR_TICKCOUNT_HIGH1TIME 0x7FFE0324 20 | #define ADDR_TICKCOUNTLOWDEPRECATED 0x7FFE0000 21 | #define KUSD_INTERRUPTTIME_HIGH2TIME (*((DWORD*)ADDR_INTERRUPTTIME_HIGH2TIME)) 22 | #define KUSD_INTERRUPTTIME_LOWPART (*((DWORD*)ADDR_INTERRUPTTIME_LOWPART)) 23 | #define KUSD_INTERRUPTTIME_HIGH1TIME (*((DWORD*)ADDR_INTERRUPTTIME_HIGH1TIME)) 24 | #define KUSD_SYSTEMTIME_HIGH2TIME (*((DWORD*)ADDR_SYSTEMTIME_HIGH2TIME)) 25 | #define KUSD_SYSTEMTIME_LOWPART (*((DWORD*)ADDR_SYSTEMTIME_LOWPART)) 26 | #define KUSD_SYSTEMTIME_HIGH1TIME (*((DWORD*)ADDR_SYSTEMTIME_HIGH1TIME)) 27 | #define KUSD_TICKCOUNT_HIGH2TIME (*((DWORD*)ADDR_TICKCOUNT_HIGH2TIME)) 28 | #define KUSD_TICKCOUNT_LOWPART (*((DWORD*)ADDR_TICKCOUNT_LOWPART)) 29 | #define KUSD_TICKCOUNT_HIGH1TIME (*((DWORD*)ADDR_TICKCOUNT_HIGH1TIME)) 30 | #define KUSD_TICKCOUNTLOWDEPRECATED (*((DWORD*)ADDR_TICKCOUNTLOWDEPRECATED)) 31 | 32 | static NTQUERYSYSTEMTIME nt_qst = NULL; 33 | static ULONGLONG start_time; 34 | static DWORD pid = 0; 35 | static HANDLE target; 36 | static int done = 0; 37 | 38 | void update_shared_data_time(void) 39 | { 40 | LARGE_INTEGER now, start, irq; 41 | nt_qst(&now); 42 | 43 | irq.QuadPart = (now.QuadPart - start_time); 44 | 45 | KUSD_INTERRUPTTIME_HIGH2TIME = irq.HighPart; 46 | KUSD_INTERRUPTTIME_LOWPART = irq.LowPart; 47 | KUSD_INTERRUPTTIME_HIGH1TIME = irq.HighPart; 48 | 49 | KUSD_SYSTEMTIME_HIGH2TIME = now.HighPart; 50 | KUSD_SYSTEMTIME_LOWPART = now.LowPart; 51 | KUSD_SYSTEMTIME_HIGH1TIME = now.HighPart; 52 | 53 | start.QuadPart = irq.QuadPart / 10000; 54 | 55 | KUSD_TICKCOUNT_HIGH2TIME = start.HighPart; 56 | KUSD_TICKCOUNT_LOWPART = start.LowPart; 57 | KUSD_TICKCOUNT_HIGH1TIME = start.HighPart; 58 | KUSD_TICKCOUNTLOWDEPRECATED = start.LowPart; 59 | } 60 | 61 | DWORD wait_for_swtor(void) 62 | { 63 | fprintf(stderr, "Waiting for swtor...\n"); 64 | fflush(stderr); 65 | 66 | DWORD swtor_pid = 0; 67 | PROCESSENTRY32 p_entry; 68 | p_entry.dwSize = sizeof(PROCESSENTRY32); 69 | HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 70 | 71 | Process32First(h, &p_entry); 72 | 73 | while (1) { 74 | if (!Process32Next(h, &p_entry)) { 75 | CloseHandle(h); 76 | h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 77 | Process32First(h, &p_entry); 78 | } 79 | if (strcmp(p_entry.szExeFile, "swtor.exe") == 0) { 80 | swtor_pid = p_entry.th32ProcessID; 81 | fprintf(stderr, "Found, PID: %ld\n", swtor_pid); 82 | break; 83 | } 84 | } 85 | 86 | CloseHandle(h); 87 | 88 | return swtor_pid; 89 | } 90 | 91 | void copy_to_target(void) 92 | { 93 | DWORD out; 94 | WriteProcessMemory(target, (LPVOID)ADDR_INTERRUPTTIME_HIGH2TIME, 95 | (LPCVOID)ADDR_INTERRUPTTIME_HIGH2TIME, sizeof(DWORD), &out); 96 | WriteProcessMemory(target, (LPVOID)ADDR_INTERRUPTTIME_LOWPART, 97 | (LPCVOID)ADDR_INTERRUPTTIME_LOWPART, sizeof(DWORD), &out); 98 | WriteProcessMemory(target, (LPVOID)ADDR_INTERRUPTTIME_HIGH1TIME, 99 | (LPCVOID)ADDR_INTERRUPTTIME_HIGH1TIME, sizeof(DWORD), &out); 100 | WriteProcessMemory(target, (LPVOID)ADDR_SYSTEMTIME_HIGH2TIME, 101 | (LPCVOID)ADDR_SYSTEMTIME_HIGH2TIME, sizeof(DWORD), &out); 102 | WriteProcessMemory(target, (LPVOID)ADDR_SYSTEMTIME_LOWPART, 103 | (LPCVOID)ADDR_SYSTEMTIME_LOWPART, sizeof(DWORD), &out); 104 | WriteProcessMemory(target, (LPVOID)ADDR_SYSTEMTIME_HIGH1TIME, 105 | (LPCVOID)ADDR_SYSTEMTIME_HIGH1TIME, sizeof(DWORD), &out); 106 | WriteProcessMemory(target, (LPVOID)ADDR_TICKCOUNT_HIGH2TIME, 107 | (LPCVOID)ADDR_TICKCOUNT_HIGH2TIME, sizeof(DWORD), &out); 108 | WriteProcessMemory(target, (LPVOID)ADDR_TICKCOUNT_LOWPART, 109 | (LPCVOID)ADDR_TICKCOUNT_LOWPART, sizeof(DWORD), &out); 110 | WriteProcessMemory(target, (LPVOID)ADDR_TICKCOUNT_HIGH1TIME, 111 | (LPCVOID)ADDR_TICKCOUNT_HIGH1TIME, sizeof(DWORD), &out); 112 | WriteProcessMemory(target, (LPVOID)ADDR_TICKCOUNTLOWDEPRECATED, 113 | (LPCVOID)ADDR_TICKCOUNTLOWDEPRECATED, sizeof(DWORD), &out); 114 | } 115 | 116 | DWORD WINAPI shared_data_thread(LPVOID arg) 117 | { 118 | (void)arg; 119 | 120 | while (!done) { 121 | update_shared_data_time(); 122 | copy_to_target(); 123 | Sleep(15); 124 | } 125 | 126 | return 0; 127 | } 128 | 129 | DWORD WINAPI is_target_dead_thread(LPVOID arg) 130 | { 131 | (void)arg; 132 | 133 | DWORD ret; 134 | 135 | while (1) { 136 | HANDLE swtor = OpenProcess(SYNCHRONIZE, FALSE, pid); 137 | ret = WaitForSingleObject(swtor, 0); 138 | CloseHandle(swtor); 139 | if (ret != WAIT_TIMEOUT) { 140 | done = 1; 141 | break; 142 | } 143 | Sleep(250); 144 | } 145 | 146 | return 0; 147 | } 148 | 149 | int main(void) 150 | { 151 | HMODULE ntdll = LoadLibrary("ntdll"); 152 | 153 | SYSTEM_TIMEOFDAY_INFORMATION ti; 154 | NTQUERYSYSTEMINFORMATION nt_qsi = 155 | (NTQUERYSYSTEMINFORMATION)GetProcAddress(ntdll, "NtQuerySystemInformation"); 156 | nt_qst = (NTQUERYSYSTEMTIME)GetProcAddress(ntdll, "NtQuerySystemTime"); 157 | FreeLibrary(ntdll); 158 | 159 | nt_qsi(SystemTimeOfDayInformation, &ti, sizeof(ti), NULL); 160 | start_time = ti.BootTime.QuadPart; 161 | 162 | pid = wait_for_swtor(); 163 | target = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, pid); 164 | 165 | HANDLE threads[2]; 166 | threads[0] = CreateThread(NULL, 0, shared_data_thread, NULL, 0, NULL); 167 | threads[1] = CreateThread(NULL, 0, is_target_dead_thread, NULL, 0, NULL); 168 | 169 | fprintf(stderr, "Waiting for threads to end..\n"); 170 | fflush(stderr); 171 | 172 | WaitForMultipleObjects(2, threads, TRUE, INFINITE); 173 | 174 | CloseHandle(threads[0]); 175 | CloseHandle(threads[1]); 176 | CloseHandle(target); 177 | 178 | return 0; 179 | } 180 | 181 | -------------------------------------------------------------------------------- /launcher.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # All cudo's goes towards the original script! The added script below is purely cosmetic in comparison (in that the new part only automates a previously manual step). 4 | 5 | unset OPTIMUS_PREFIX 6 | # In case of an optimus-enabled laptop, the use of primusrun is recommended over optirun. 7 | # Don't uncomment this line in any other case. 8 | # OPTIMUS_PREFIX=" primusrun" 9 | 10 | ### BELOW HAS BEEN ADDED TO TURN OFF BIT RUNNER AND SUPPORT PLAYONLINUX ### 11 | 12 | #Regardless of where our launcher is located, lets automatically find it and use it! Even if this script is in a parent directory. 13 | settingslocation=`echo \'``find . -name "launcher.settings" | grep "Star Wars - The Old Republic/launcher.settings"``echo \'` 14 | launcherlocation=`echo \'``find . -name "launcher.exe" | grep "Star Wars - The Old Republic/launcher.exe"``echo \'` 15 | 16 | if [ -z "$settingslocation" ]; then 17 | settingslocation=`echo \'``find . -name "launcher.settings" | grep "./launcher.settings"``echo \'` 18 | fi 19 | 20 | if [ -z "$launcherlocation" ]; then 21 | launcherlocation=`echo \'``find . -name "launcher.exe" | grep "./launcher.exe"``echo \'` 22 | fi 23 | 24 | #This is our main command! 25 | LAUNCHER_COMMAND="wine $launcherlocation" 26 | 27 | #The text to replace in order to turn off bit runner! 28 | sourcetext=`echo \'`'"PatchingMode": "{ \\"swtor\\": \\"BR\\" }"'`echo \'` 29 | replacetext=`echo \'`'"PatchingMode": "{ \\"swtor\\": \\"SSN\\" }"'`echo \'` 30 | 31 | #Is launcher.settings setup for running bit runner? 32 | cmd="grep -i $sourcetext $settingslocation" 33 | istextfound=`eval $cmd` 34 | 35 | if [ -n "$istextfound" ]; then 36 | echo "This will update the launcher.settings file so that bitraider is disabled!" 37 | echo 38 | echo "Replacing: $sourcetext" 39 | echo "with: $replacetext" 40 | echo 41 | 42 | islaunchersettingsfixed=n 43 | fi 44 | 45 | #Has launcher.settings had bit runner turned off? 46 | cmd="grep -i $replacetext $settingslocation" 47 | istextfound=`eval $cmd` 48 | 49 | if [ -n "$istextfound" ]; then 50 | echo "This file has been updated so bitraider is disabled." 51 | echo 52 | echo "Ready to install!" 53 | echo 54 | 55 | islaunchersettingsfixed=y 56 | fi 57 | 58 | #If launcher.settings doesn't even have bit runner turned on or off, assume this is the first run of the launcher! 59 | # If it runs flawlessly, there will be no need to turn off bit runner. This script will not need to be ran again! 60 | if [ -z "$islaunchersettingsfixed" ]; then 61 | echo "The launcher has never been ran. Please run the launcher for the first time." 62 | echo "Login using your user name and password. Then run the launcher." 63 | echo 64 | echo "1. If the launcher fails: This is good! Please re-run this script. It will turn off bitraider the second time around." 65 | echo "2. If the launcher succeeds: The first time, there is no need to run this script again. Please run the installer directly next time!" 66 | echo 67 | fi 68 | 69 | echo "Would you like to Continue? [y/n]" 70 | read input 71 | 72 | if [ ! $input = y ]; then 73 | echo 74 | echo "Thank you for using this script. You have choosen $input which is not lower case y. Exiting..." 75 | echo 76 | 77 | exit 78 | fi 79 | 80 | #Only backup launcher.settings and turn off bit runner in launcher.settings when bit runner is enabled. 81 | if [ $islaunchersettingsfixed = n ]; then 82 | echo "Backing up launcher.settings to launcher.settings`date +%y%m%d_%H%M`.bak" 83 | settingsbackuplocation="$settingslocation`date +%y%m%d_%H%M`.bak" 84 | 85 | #Makes a backup of launcher.settings! This only gets done when launcher.settings does not have Bit Runner disabled. 86 | cmd="cp $settingslocation $settingsbackuplocation" 87 | eval $cmd 88 | 89 | echo 90 | echo "Making changes to launcher.settings..." 91 | 92 | #Removes ' from around these statements. Sed will have its own ' around both statements. 93 | sourcetextstring=`echo $sourcetext | sed "s|'||g"` 94 | replacetextstring=`echo $replacetext | sed "s|'||g"` 95 | 96 | #Replaces the desired text in launcher.settings 97 | cmd="sed 's|$sourcetextstring|$replacetextstring|g' $settingsbackuplocation > $settingslocation" 98 | 99 | echo 100 | echo "It is strongly advised to allow bit runner to be turned off. Unless you have a very good reason not to, please select y here. Turn off bit runner? [Y/n]" 101 | read turnoffbitrunner 102 | 103 | if [ ! $turnoffbitrunner = n ]; then 104 | eval $cmd 105 | fi 106 | 107 | echo 108 | echo "Finished updating launcher.settings! You will now be able to use the installer to download swtor!" 109 | 110 | #Cleanup our local variables 111 | unset turnoffbitrunner 112 | unset replacetextstring 113 | unset sourcetextstring 114 | unset settingsbackuplocation 115 | fi 116 | 117 | echo 118 | echo "Is your wine environment in 64 bit mode? (Choose y if unsure. If running this on playonlinux 'in 32 bit mode', choose n) [Y/n]" 119 | read specifyarch 120 | 121 | echo 122 | echo "Would you like to configure wine to use a custom prefix? (Choose y if unsure. If running this on playonlinux, choose n) [Y/n]" 123 | read specifyprefix 124 | 125 | # Set up a new wineprefix in the game directory, and reduce debugging to improve performance. 126 | # If you don't like it there, or running the script from somewhere else, change it. 127 | # Please note that WINEARCH=win32 is REQUIRED. 128 | if [ $specifyarch = y -o $specifyarch = Y -o $specifyarch = yes -o $specifyarch = Yes -o $specifyarch = YES ]; then 129 | export WINEARCH=win32 130 | export WINEDEBUG=-all 131 | fi 132 | 133 | if [ $specifyprefix = y -o $specifyprefix = Y -o $specifyprefix = yes -o $specifyprefix = Yes -o $specifyprefix = YES ]; then 134 | export WINEPREFIX="$( pwd )/wineprefix" 135 | fi 136 | 137 | # Clean up after ourselves. 138 | unset settingslocation 139 | unset launcherlocation 140 | 141 | unset islauchersettingsfixed 142 | unset specifyarch 143 | unset specifyprefix 144 | unset istextfound 145 | unset input 146 | unset cmd 147 | 148 | ### FROM HERE ON OUT IS THE ORIGINAL SCRIPT ### 149 | 150 | # Check if we have swtor_fix.exe, and download it if we don't. 151 | # This can be placed anywhere on the system, and must be run parallel to the game. 152 | 153 | if [ ! -f swtor_fix.exe ]; then 154 | wget -O swtor_fix.exe https://github.com/aljen/swtor_fix/raw/master/swtor_fix.exe 155 | fi 156 | 157 | # Start it parallely. 158 | wine swtor_fix.exe & 159 | 160 | # Give it a sec to fire up. 161 | sleep 1 162 | 163 | # Install and set up components in wineprefix. 164 | # Since that command does nothing if already ran, we need no checks there. 165 | winetricks msvcp90=native d3dx9_36 vcrun2008 msls31 winhttp 166 | 167 | # Here we come! 168 | eval $OPTIMUS_PREFIX $LAUNCHER_COMMAND 169 | 170 | # Since wait for swtor_fix.exe to finish. 171 | wait $! 172 | 173 | # Clean up after ourselves. 174 | unset WINEARCH 175 | unset WINEPREFIX 176 | unset WINEDEBUG 177 | 178 | --------------------------------------------------------------------------------