Advertisement
Guest User

Untitled

a guest
Nov 14th, 2019
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.69 KB | None | 0 0
  1. // GTA: SA ASI Loader 1.2
  2. // Written by Silent
  3. // Based on ASI Loader by Stanislav "listener" Golovin
  4. // Initialization part made by NTAuthority
  5.  
  6. #include <windows.h>
  7. #include <iostream>
  8.  
  9. BYTE      originalCode[5];
  10. BYTE*      originalEP = 0;
  11. HINSTANCE    hExecutableInstance;
  12.  
  13. //=============================================================================
  14. // vorbisfile connector
  15. extern "C" {
  16. struct ov_callbacks {
  17. size_t (*read_func) (void* ptr, size_t size, size_t nmemb, void* datasource);
  18. int (*seek_func) (void* datasource, long long offset, int whence);
  19. int (*close_func) (void* datasource);
  20. long (*tell_func) (void* datasource);
  21. };
  22.  
  23. void* __ov_open_callbacks;
  24. __declspec(dllexport, naked) int ov_open_callbacks(void* datasource, void* vf, char* initial, long ibytes, ov_callbacks callbacks)
  25. { _asm jmp __ov_open_callbacks }
  26.  
  27. void* __ov_clear;
  28. __declspec(dllexport, naked) int ov_clear(void* vf)
  29. { _asm jmp __ov_clear }
  30.  
  31. void* __ov_time_total;
  32. __declspec(dllexport, naked) double ov_time_total (void* vf, int i)
  33. { _asm jmp __ov_time_total }
  34.  
  35. void* __ov_time_tell;
  36. __declspec(dllexport, naked) double ov_time_tell(void* vf)
  37. { _asm jmp __ov_time_tell }
  38.  
  39. void* __ov_read;
  40. __declspec(dllexport, naked) long ov_read(void* vf, char* buffer, int length, int bigendianp, int word, int sgned, int* bitstream)
  41. { _asm jmp __ov_read }
  42.  
  43. void* __ov_info;
  44. __declspec(dllexport, naked) void* ov_info(void* vf, int link)
  45. { _asm jmp __ov_info }
  46.  
  47. void* __ov_time_seek;
  48. __declspec(dllexport, naked) int ov_time_seek(void* vf, double pos)
  49. { _asm jmp __ov_time_seek }
  50.  
  51. void* __ov_time_seek_page;
  52. __declspec(dllexport, naked) int ov_time_seek_page(void* vf, double pos)
  53. { _asm jmp __ov_time_seek_page }
  54.  
  55. }
  56.  
  57. struct ExcludedEntry {
  58. char*   entry;
  59. ExcludedEntry*    prev;
  60. ExcludedEntry*    next;
  61. };
  62.  
  63. struct ExcludedEntriesList {
  64. ExcludedEntry*    first;
  65. ExcludedEntry*    last;
  66. };
  67.  
  68. void ExcludedEntriesListInit(ExcludedEntriesList* list)
  69. {
  70. list->first = NULL;
  71. list->last = NULL;
  72. }
  73.  
  74. void ExcludedEntriesListPush(ExcludedEntriesList* list, const char* entryName)
  75. {
  76. ExcludedEntry*  newEntry = (ExcludedEntry*)malloc(sizeof(ExcludedEntry));
  77. int    length = strlen(entryName) + 1;
  78. if ( !list->first )
  79. list->first = newEntry;
  80. else
  81. list->last->next = newEntry;
  82.  
  83. newEntry->prev = list->last;
  84. newEntry->next = NULL;
  85. list->last = newEntry;
  86.  
  87. newEntry->entry = (char*)malloc(length);
  88. strncpy(newEntry->entry, entryName, length);
  89. }
  90.  
  91. bool ExcludedEntriesListHasEntry(ExcludedEntriesList* list, const char* entryName)
  92. {
  93. ExcludedEntry*    it = list->first;
  94. while ( it )
  95. {
  96. if ( !_stricmp(it->entry, entryName) )
  97. {
  98. // It has an entry, we can pop it now
  99. if ( it->next )
  100. it->next->prev = it->prev;
  101. if ( it->prev )
  102. it->prev->next = it->next;
  103.  
  104. if ( list->first == it )
  105. list->first = it->next;
  106.  
  107. free(it->entry);
  108. free(it);
  109. return true;
  110. }
  111. it = it->next;
  112. }
  113.  
  114. return false;
  115. }
  116.  
  117. void ExcludedEntriesListFree(ExcludedEntriesList* list)
  118. {
  119. ExcludedEntry*    it = list->first;
  120. while ( it )
  121. {
  122. ExcludedEntry* nextEntry = it->next;
  123. free(it->entry);
  124. free(it);
  125. it = nextEntry;
  126. }
  127. }
  128.  
  129. void FindFiles(WIN32_FIND_DATA* fd, ExcludedEntriesList* list)
  130. {
  131. HANDLE asiFile = FindFirstFile ("*.asi", fd);
  132. if (asiFile != INVALID_HANDLE_VALUE)
  133. {
  134.  
  135. do {
  136. if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  137.  
  138. unsigned int pos = 5;
  139. while (fd->cFileName[pos])
  140. ++pos;
  141. if (fd->cFileName[pos-4] == '.' &&
  142. (fd->cFileName[pos-3] == 'a' || fd->cFileName[pos-3] == 'A') &&
  143. (fd->cFileName[pos-2] == 's' || fd->cFileName[pos-2] == 'S') &&
  144. (fd->cFileName[pos-1] == 'i' || fd->cFileName[pos-1] == 'I'))
  145. {
  146. if ( !list || !ExcludedEntriesListHasEntry(list, fd->cFileName) )
  147. LoadLibrary (fd->cFileName);
  148. }
  149. }
  150.  
  151. } while (FindNextFile (asiFile, fd));
  152. FindClose (asiFile);
  153. }
  154. }
  155.  
  156. void LoadPlugins()
  157. {
  158. HMODULE vorbisHooked = LoadLibrary ("vorbishooked");
  159. if ( vorbisHooked )
  160. {
  161. __ov_open_callbacks = GetProcAddress (vorbisHooked, "ov_open_callbacks");
  162. __ov_clear = GetProcAddress (vorbisHooked, "ov_clear");
  163. __ov_time_total = GetProcAddress (vorbisHooked, "ov_time_total");
  164. __ov_time_tell = GetProcAddress (vorbisHooked, "ov_time_tell");
  165. __ov_read = GetProcAddress (vorbisHooked, "ov_read");
  166. __ov_info = GetProcAddress (vorbisHooked, "ov_info");
  167. __ov_time_seek = GetProcAddress (vorbisHooked, "ov_time_seek");
  168. __ov_time_seek_page = GetProcAddress (vorbisHooked, "ov_time_seek_page");
  169.  
  170. // Regular ASI Loader
  171. WIN32_FIND_DATA fd;
  172. char   moduleName[MAX_PATH];
  173. char   preparedPath[128];    // stores scripts\*exename*\settings.ini
  174. char*   tempPointer;
  175. int    nWantsToLoadPlugins;
  176. int    nThatExeWantsPlugins;
  177.  
  178. GetModuleFileName(NULL, moduleName, MAX_PATH);
  179. tempPointer = strrchr(moduleName, '.');
  180. *tempPointer = '\0';
  181.  
  182. tempPointer = strrchr(moduleName, '\\');
  183. strncpy(preparedPath, "scripts", 8);
  184. strcat(preparedPath, tempPointer);
  185. strcat(preparedPath, "\\settings.ini");
  186.  
  187. // Before we load any ASI files, let's see if user wants to do it at all
  188. nWantsToLoadPlugins = GetPrivateProfileInt("globalsets", "loadplugins", TRUE, "scripts\\global.ini");
  189. // Or perhaps this EXE wants to override global settings?
  190. nThatExeWantsPlugins = GetPrivateProfileInt("exclusivesets", "loadplugins", -1, preparedPath);
  191.  
  192. if ( nThatExeWantsPlugins )    // Will not process only if this EXE wishes not to load anything but its exclusive plugins
  193. {
  194. if ( nWantsToLoadPlugins || nThatExeWantsPlugins == TRUE )
  195. {
  196. // Load excludes
  197. ExcludedEntriesList    excludes;
  198.  
  199. ExcludedEntriesListInit(&excludes);
  200. if ( FILE* iniFile = fopen(preparedPath, "rt") )
  201. {
  202. char    line[256];
  203. bool    bItsExcludesList = false;
  204.  
  205. while ( fgets(line, 256, iniFile) )
  206. {
  207. char*    newline = strchr(line, '\n');
  208.  
  209. if ( newline )
  210. *newline = '\0';
  211.  
  212. if ( bItsExcludesList )
  213. {
  214. if ( line[0] && line[0] != ';' )
  215. ExcludedEntriesListPush(&excludes, line);
  216. }
  217. else
  218. {
  219. if ( !_stricmp(line, "[excludes]") )
  220. bItsExcludesList = true;
  221. }
  222. }
  223.  
  224. fclose(iniFile);
  225. }
  226. FindFiles(&fd, &excludes);
  227. if ( SetCurrentDirectory("scripts\\") )
  228. {
  229. FindFiles(&fd, &excludes);
  230. if ( SetCurrentDirectory(tempPointer + 1) )
  231. {
  232. FindFiles(&fd, NULL);    // Exclusive plugins are not being excluded
  233. SetCurrentDirectory("..\\..\\");
  234. }
  235. else
  236. SetCurrentDirectory("..\\");
  237. }
  238.  
  239. // Free the remaining excludes
  240. ExcludedEntriesListFree(&excludes);
  241. }
  242. }
  243. else
  244. {
  245. // Load only exclusive plugins, if exists
  246. // We need to cut settings.ini from the path again
  247. tempPointer = strrchr(preparedPath, '\\');
  248. tempPointer[1] = '\0';
  249. if ( SetCurrentDirectory(preparedPath) )
  250. {
  251. FindFiles(&fd, NULL);
  252. SetCurrentDirectory("..\\..\\");
  253. }
  254. }
  255. }
  256.  
  257. // Unprotect the module NOW (CLEO 4.1.1.30f crash fix)
  258. IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((DWORD)hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew);
  259.  
  260. SIZE_T size = ntHeader->OptionalHeader.SizeOfImage;
  261. DWORD oldProtect;
  262. VirtualProtect((VOID*)hExecutableInstance, size, PAGE_EXECUTE_READWRITE, &oldProtect);
  263. }
  264.  
  265. static bool   bLoadedPluginsYet = false;
  266.  
  267. void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo)
  268. {
  269. if ( !bLoadedPluginsYet )
  270. {
  271. // At the time this is called, the EXE is fully decrypted - we don't need any tricks from the ASI side
  272. LoadPlugins();
  273. bLoadedPluginsYet = true;
  274. }
  275. GetStartupInfoA(lpStartupInfo);
  276. }
  277.  
  278. void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
  279. {
  280. if ( !bLoadedPluginsYet )
  281. {
  282. // At the time this is called, the EXE is fully decrypted - we don't need any tricks from the ASI side
  283. LoadPlugins();
  284. bLoadedPluginsYet = true;
  285. }
  286. GetStartupInfoW(lpStartupInfo);
  287. }
  288.  
  289. void PatchIAT()
  290. {
  291. // Find IAT
  292. IMAGE_NT_HEADERS*   ntHeader = (IMAGE_NT_HEADERS*)((DWORD)hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew);
  293. IMAGE_IMPORT_DESCRIPTOR*    pImports = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD)hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  294. DWORD      nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;
  295.  
  296. // Find kernel32.dll
  297. for ( DWORD i = 0; i < nNumImports; i++ )
  298. {
  299. if ( !_stricmp((const char*)((DWORD)hExecutableInstance + pImports->Name), "KERNEL32.DLL") )
  300. {
  301. IMAGE_IMPORT_BY_NAME**  pFunctions = (IMAGE_IMPORT_BY_NAME**)((DWORD)hExecutableInstance + pImports->OriginalFirstThunk);
  302.  
  303. // kernel32.dll found, find GetStartupInfoA
  304. for ( DWORD j = 0; pFunctions[j]; j++ )
  305. {
  306. if ( !_stricmp((const char*)((DWORD)hExecutableInstance + pFunctions[j]->Name), "GetStartupInfoA") )
  307. {
  308. // Overwrite the address with the address to a custom GetStartupInfoA
  309. DWORD  dwProtect[2];
  310. DWORD*  pAddress = &((DWORD*)((DWORD)hExecutableInstance + pImports->FirstThunk))[j];
  311.  
  312. VirtualProtect(pAddress, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
  313. *pAddress = (DWORD)CustomGetStartupInfoA;
  314. VirtualProtect(pAddress, sizeof(DWORD), dwProtect[0], &dwProtect[1]);
  315.  
  316. // return to the original EP
  317. *(DWORD*)originalEP = *(DWORD*)&originalCode;
  318. *(BYTE*)(originalEP+4) = originalCode[4];
  319. return;
  320. }
  321.  
  322. // For new SA Steam EXE
  323. if ( !_stricmp((const char*)((DWORD)hExecutableInstance + pFunctions[j]->Name), "GetStartupInfoW") )
  324. {
  325. // Overwrite the address with the address to a custom GetStartupInfoA
  326. DWORD  dwProtect[2];
  327. DWORD*  pAddress = &((DWORD*)((DWORD)hExecutableInstance + pImports->FirstThunk))[j];
  328.  
  329. VirtualProtect(pAddress, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwProtect[0]);
  330. *pAddress = (DWORD)CustomGetStartupInfoW;
  331. VirtualProtect(pAddress, sizeof(DWORD), dwProtect[0], &dwProtect[1]);
  332.  
  333. // return to the original EP
  334. *(DWORD*)originalEP = *(DWORD*)&originalCode;
  335. *(BYTE*)(originalEP+4) = originalCode[4];
  336. return;
  337. }
  338. }
  339. }
  340. pImports++;
  341. }
  342.  
  343. // No luck. Oh well.
  344. // return to the original EP anyway
  345. *(DWORD*)originalEP = *(DWORD*)&originalCode;
  346. *(BYTE*)(originalEP+4) = originalCode[4];
  347. }
  348.  
  349. void __declspec(naked) Main_DoInit()
  350. {
  351. _asm
  352. {
  353. call    PatchIAT
  354. jmp  originalEP
  355. }
  356. }
  357.  
  358. BOOL APIENTRY DllMain( HMODULE hModule,
  359. DWORD ul_reason_for_call,
  360. LPVOID lpReserved
  361. )
  362. {
  363. if ( ul_reason_for_call == DLL_PROCESS_ATTACH )
  364. {
  365. hExecutableInstance = GetModuleHandle(NULL); // passing NULL should be safe even with the loader lock being held (according to ReactOS ldr.c)
  366.  
  367. if (hExecutableInstance)
  368. {
  369. IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)((DWORD)hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew);
  370. BYTE* ep = (BYTE*)((DWORD)hExecutableInstance + ntHeader->OptionalHeader.AddressOfEntryPoint);
  371.  
  372. // Unprotect the entry point
  373. DWORD oldProtect;
  374. VirtualProtect(ep, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
  375.  
  376. // back up original code
  377. *(DWORD*)&originalCode = *(DWORD*)ep;
  378. originalCode[4] = *(ep+4);
  379.  
  380. // patch to call our EP
  381. int newEP = (int)Main_DoInit - ((int)ep + 5);
  382. ep[0] = 0xE9;
  383.  
  384. *(int*)&ep[1] = newEP;
  385.  
  386. originalEP = ep;
  387. }
  388. }
  389. return TRUE;
  390. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement