SHARE
TWEET

Untitled

a guest Aug 25th, 2019 66 in 338 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*****************************************************************************
  2.  *
  3.  *  PROJECT:     Multi Theft Auto v1.0
  4.  *  LICENSE:     See LICENSE in the top level directory
  5.  *  FILE:        CExePatchedStatus.cpp
  6.  *
  7.  *  Multi Theft Auto is available from http://www.multitheftauto.com/
  8.  *
  9.  *****************************************************************************/
  10.  
  11. #include "StdInc.h"
  12.  
  13. //////////////////////////////////////////////////////////
  14. //
  15. // GetExePatchedStatus
  16. //
  17. // Check which patches are currently applied
  18. //
  19. //////////////////////////////////////////////////////////
  20. SExePatchedStatus GetExePatchedStatus(bool bUseExeCopy)
  21. {
  22.     SString strGTAEXEPath = GetExePathFilename(bUseExeCopy);
  23.  
  24.     SExePatchedStatus status;
  25.     status.bTimestamp = UpdatePatchStatusTimestamp(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  26.     status.bLargeMem = UpdatePatchStatusLargeMem(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  27.     status.bDep = UpdatePatchStatusDep(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  28.     status.bNvightmare = UpdatePatchStatusNvightmare(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  29.     status.bAltModules = UpdatePatchStatusAltModules(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  30.     status.bEntryPoint = UpdatePatchStatusEntryPoint(strGTAEXEPath, PATCH_CHECK) == PATCH_CHECK_RESULT_ON;
  31.  
  32.     return status;
  33. }
  34.  
  35. //////////////////////////////////////////////////////////
  36. //
  37. // GetExePatchRequirements
  38. //
  39. // Check which patches should be applied
  40. //
  41. //////////////////////////////////////////////////////////
  42. SExePatchedStatus GetExePatchRequirements()
  43. {
  44.     SExePatchedStatus status;
  45.     status.bTimestamp = GetApplicationSettingInt("aero-enabled") ? true : false;
  46.     status.bLargeMem = true;
  47.     status.bDep = GetGtaFileVersion(GetExePathFilename(false)) != EGtaFileVersion::Encrypted;
  48.     status.bNvightmare = GetApplicationSettingInt("nvhacks", "optimus-export-enablement") ? true : false;
  49.     status.bAltModules = GetPatchRequirementAltModules();
  50.     status.bEntryPoint = GetPatchRequirementEntryPoint();
  51.  
  52.     return status;
  53. }
  54.  
  55. //////////////////////////////////////////////////////////
  56. //
  57. // SetExePatchedStatus
  58. //
  59. // Apply selected patches to exe
  60. // Return false if needs admin access
  61. //
  62. //////////////////////////////////////////////////////////
  63. bool SetExePatchedStatus(bool bUseExeCopy, const SExePatchedStatus& status)
  64. {
  65.     SString strGTAEXEPath = GetExePathFilename(bUseExeCopy);
  66.  
  67.     bool bReqAdmin = false;
  68.     bReqAdmin |= UpdatePatchStatusTimestamp(strGTAEXEPath, status.bTimestamp ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  69.     bReqAdmin |= UpdatePatchStatusLargeMem(strGTAEXEPath, status.bLargeMem ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  70.     bReqAdmin |= UpdatePatchStatusDep(strGTAEXEPath, status.bDep ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  71.     bReqAdmin |= UpdatePatchStatusNvightmare(strGTAEXEPath, status.bNvightmare ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  72.     bReqAdmin |= UpdatePatchStatusAltModules(strGTAEXEPath, status.bAltModules ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  73.     bReqAdmin |= UpdatePatchStatusEntryPoint(strGTAEXEPath, status.bEntryPoint ? PATCH_SET_ON : PATCH_SET_OFF) == PATCH_SET_RESULT_REQ_ADMIN;
  74.  
  75.     return !bReqAdmin;
  76. }
  77.  
  78. //////////////////////////////////////////////////////////
  79. //
  80. // ShouldUseExeCopy
  81. //
  82. // Returns true if patches should be applied to exe copy
  83. //
  84. //////////////////////////////////////////////////////////
  85. bool ShouldUseExeCopy()
  86. {
  87.     SString strUseCopyReason;
  88.     if (GetApplicationSettingInt("nvhacks", "optimus"))
  89.         strUseCopyReason = GetApplicationSettingInt("nvhacks", "optimus-rename-exe") == 0 ? "" : "optimus-rename-exe";
  90.     else
  91.         strUseCopyReason = GetApplicationSettingInt("driver-overrides-disabled") == 0 ? "" : "driver-overrides-disabled";
  92.  
  93.     if (GetPatchRequirementAltModules())
  94.         strUseCopyReason += " AltModules";
  95.  
  96.     if (GetPatchRequirementEntryPoint())
  97.         strUseCopyReason += " EntryPoint";
  98.  
  99.     if (RequiresAltTabFix())
  100.         strUseCopyReason += " AltTabFix";
  101.  
  102.     // Log reason for using proxy_sa
  103.     static SString strUseCopyReasonPrevious;
  104.     if (strUseCopyReasonPrevious != strUseCopyReason)
  105.     {
  106.         WriteDebugEventAndReport(3500, SString("Using proxy_sa because: %s", *strUseCopyReason));
  107.         strUseCopyReasonPrevious = strUseCopyReason;
  108.     }
  109.     return !strUseCopyReason.empty();
  110. }
  111.  
  112. //////////////////////////////////////////////////////////
  113. //
  114. // RequiresAltTabFix
  115. //
  116. // Return true if there might be an alt-tab black screen problem when using gta_sa.exe
  117. //
  118. //////////////////////////////////////////////////////////
  119. bool RequiresAltTabFix()
  120. {
  121.     // Exception for optimus because of better hi-perf detection when using gta_sa.exe
  122.     if (GetApplicationSettingInt("nvhacks", "optimus"))
  123.         return false;
  124.  
  125.     // Check for problem combo of: Windows 10 + NVidia card + full screen
  126.     if (IsWindows10OrGreater() && GetApplicationSettingInt("nvhacks", "nvidia"))
  127.     {
  128.         // Slighty hacky way of checking in-game settings
  129.         SString strCoreConfig;
  130.         FileLoad(CalcMTASAPath(PathJoin("mta", "config", "coreconfig.xml")), strCoreConfig);
  131.         int iWindowed = atoi(strCoreConfig.SplitRight("<display_windowed>"));
  132.         int iFullscreenStyle = atoi(strCoreConfig.SplitRight("<display_fullscreen_style>"));
  133.         if (iWindowed == 0 && iFullscreenStyle == 0)            // 0=FULLSCREEN_STANDARD
  134.             return true;
  135.     }
  136.     return false;
  137. }
  138.  
  139. //////////////////////////////////////////////////////////
  140. //
  141. // GetPatchExeAdminReason
  142. //
  143. // Get reason for user message
  144. //
  145. //////////////////////////////////////////////////////////
  146. SString GetPatchExeAdminReason(bool bUseExeCopy, const SExePatchedStatus& reqStatus)
  147. {
  148.     // Get current status
  149.     SExePatchedStatus status = GetExePatchedStatus(bUseExeCopy);
  150.  
  151.     // See what needs doing
  152.     if (status.bTimestamp != reqStatus.bTimestamp)
  153.         return _("Update Aero setting");
  154.     if (status.bLargeMem != reqStatus.bLargeMem)
  155.         return _("Update Large Memory setting");
  156.     if (status.bDep != reqStatus.bDep)
  157.         return _("Update DEP setting");
  158.     if (status.bNvightmare != reqStatus.bNvightmare)
  159.         return _("Update graphics driver compliance");
  160.     if (status.bAltModules != reqStatus.bAltModules)
  161.         return _("Fix file issues");
  162.     if (status.bEntryPoint != reqStatus.bEntryPoint)
  163.         return _("Fix file issues");
  164.     return _("Copy main executable to avoid graphic driver issues");
  165. }
  166.  
  167. //////////////////////////////////////////////////////////
  168. //
  169. // GetExeFileSize
  170. //
  171. //
  172. //
  173. //////////////////////////////////////////////////////////
  174. uint64 GetExeFileSize(bool bUseExeCopy)
  175. {
  176.     SString strGTAEXEPath = GetExePathFilename(bUseExeCopy);
  177.     return FileSize(strGTAEXEPath);
  178. }
  179.  
  180. //////////////////////////////////////////////////////////
  181. //
  182. // CopyExe
  183. //
  184. // Return false if needs admin access
  185. //
  186. //////////////////////////////////////////////////////////
  187. bool CopyExe()
  188. {
  189.     SString strGTAEXEPathFrom = GetExePathFilename(false);
  190.     SString strGTAEXEPathTo = GetExePathFilename(true);
  191.     if (!FileCopy(strGTAEXEPathFrom, strGTAEXEPathTo))
  192.         return false;
  193.     return true;
  194. }
  195.  
  196. //////////////////////////////////////////////////////////
  197. //
  198. // GetExePathFilename
  199. //
  200. // Return full path and filename of main or copy exe
  201. //
  202. //////////////////////////////////////////////////////////
  203. SString GetExePathFilename(bool bUseExeCopy)
  204. {
  205.     SString strGTAPath = GetGTAPath();
  206.     if (!strGTAPath.empty())
  207.     {
  208.         const char* szExeName = bUseExeCopy ? MTA_HTAEXE_NAME : MTA_GTAEXE_NAME;
  209.         SString     strGTAEXEPath = PathJoin(strGTAPath, szExeName);
  210.         return strGTAEXEPath;
  211.     }
  212.     return "unknown";
  213. }
  214.  
  215. //////////////////////////////////////////////////////////
  216. //
  217. // GetUsingExePathFilename
  218. //
  219. // Return full path and filename of exe we will probably be using
  220. //
  221. //////////////////////////////////////////////////////////
  222. SString GetUsingExePathFilename()
  223. {
  224.     return GetExePathFilename(ShouldUseExeCopy());
  225. }
  226.  
  227. //////////////////////////////////////////////////////////
  228. //
  229. // UpdatePatchStatusTimestamp
  230. //
  231. // Change the link timestamp in gta_sa.exe to trick windows 7 into using aero
  232. //
  233. //////////////////////////////////////////////////////////
  234. EPatchResult UpdatePatchStatusTimestamp(const SString& strGTAEXEPath, EPatchMode mode)
  235. {
  236.     SPEFileOffsets fileOffsets;
  237.     GetPEFileOffsets(fileOffsets, strGTAEXEPath);
  238.  
  239.     // Get the top byte of the file link timestamp
  240.     uchar ucTimeStamp = 0;
  241.     ReadFileValue(strGTAEXEPath, ucTimeStamp, fileOffsets.TimeDateStamp + 3);
  242.  
  243.     const uchar AERO_DISABLED = 0x42;
  244.     const uchar AERO_ENABLED = 0x43;
  245.  
  246.     // Return status if just checking
  247.     if (mode == PATCH_CHECK)
  248.     {
  249.         if (ucTimeStamp == AERO_ENABLED)
  250.             return PATCH_CHECK_RESULT_ON;
  251.         return PATCH_CHECK_RESULT_OFF;
  252.     }
  253.  
  254.     // Check it's a value we're expecting
  255.     bool bCanChangeAeroSetting = (ucTimeStamp == AERO_DISABLED || ucTimeStamp == AERO_ENABLED);
  256.     SetApplicationSettingInt("aero-changeable", bCanChangeAeroSetting);
  257.  
  258.     if (bCanChangeAeroSetting)
  259.     {
  260.         // Get option to set
  261.         bool  bAeroEnabled = (mode == PATCH_SET_ON);
  262.         uchar ucTimeStampRequired = bAeroEnabled ? AERO_ENABLED : AERO_DISABLED;
  263.         if (ucTimeStamp != ucTimeStampRequired)
  264.         {
  265.             // Change needed!
  266.             if (!WriteFileValue(strGTAEXEPath, ucTimeStampRequired, fileOffsets.TimeDateStamp + 3))
  267.             {
  268.                 return PATCH_SET_RESULT_REQ_ADMIN;
  269.             }
  270.         }
  271.     }
  272.     return PATCH_SET_RESULT_OK;
  273. }
  274.  
  275. //////////////////////////////////////////////////////////
  276. //
  277. // UpdatePatchStatusLargeMem
  278. //
  279. // Change the PE header to give GTA access to more memory
  280. //
  281. //////////////////////////////////////////////////////////
  282. EPatchResult UpdatePatchStatusLargeMem(const SString& strGTAEXEPath, EPatchMode mode)
  283. {
  284.     SPEFileOffsets fileOffsets;
  285.     GetPEFileOffsets(fileOffsets, strGTAEXEPath);
  286.     ushort usCharacteristics = 0;
  287.     ReadFileValue(strGTAEXEPath, usCharacteristics, fileOffsets.Characteristics);
  288.  
  289.     const ushort LARGEMEM_DISABLED = 0x10f;
  290.     const ushort LARGEMEM_ENABLED = 0x12f;
  291.  
  292.     // Return status if just checking
  293.     if (mode == PATCH_CHECK)
  294.     {
  295.         if (usCharacteristics == LARGEMEM_ENABLED)
  296.             return PATCH_CHECK_RESULT_ON;
  297.         return PATCH_CHECK_RESULT_OFF;
  298.     }
  299.  
  300.     // Check it's a value we're expecting
  301.     bool bCanChangeLargeMemSetting = (usCharacteristics == LARGEMEM_DISABLED || usCharacteristics == LARGEMEM_ENABLED);
  302.  
  303.     if (bCanChangeLargeMemSetting)
  304.     {
  305.         ushort usCharacteristicsRequired = (mode == PATCH_SET_ON) ? LARGEMEM_ENABLED : LARGEMEM_DISABLED;
  306.         dassert(usCharacteristicsRequired == LARGEMEM_ENABLED);
  307.         if (usCharacteristics != usCharacteristicsRequired)
  308.         {
  309.             // Change needed!
  310.             if (!WriteFileValue(strGTAEXEPath, usCharacteristicsRequired, fileOffsets.Characteristics))
  311.             {
  312.                 return PATCH_SET_RESULT_REQ_ADMIN;
  313.             }
  314.         }
  315.     }
  316.     else
  317.     {
  318.         WriteDebugEventAndReport(
  319.             9805, SString("Unable to set LARGE_ADDRESS_AWARE [FilePosition=0x%x Characteristics=0x%x]", fileOffsets.Characteristics, usCharacteristics));
  320.     }
  321.     return PATCH_SET_RESULT_OK;
  322. }
  323.  
  324. //////////////////////////////////////////////////////////
  325. //
  326. // UpdatePatchStatusDep
  327. //
  328. // Change the PE header to enable DEP
  329. //
  330. //////////////////////////////////////////////////////////
  331. EPatchResult UpdatePatchStatusDep(const SString& strGTAEXEPath, EPatchMode mode)
  332. {
  333.     SPEFileOffsets fileOffsets;
  334.     GetPEFileOffsets(fileOffsets, strGTAEXEPath);
  335.  
  336.     // Get the value from the header
  337.     ushort usDllCharacteristics = 0;
  338.     ReadFileValue(strGTAEXEPath, usDllCharacteristics, fileOffsets.DllCharacteristics);
  339.  
  340.     const ushort DEP_DISABLED = 0x0000;
  341.     const ushort DEP_ENABLED = 0x0100;
  342.  
  343.     // Return status if just checking
  344.     if (mode == PATCH_CHECK)
  345.     {
  346.         if (usDllCharacteristics == DEP_ENABLED)
  347.             return PATCH_CHECK_RESULT_ON;
  348.         return PATCH_CHECK_RESULT_OFF;
  349.     }
  350.  
  351.     // Check it's a value we're expecting
  352.     bool bCanChangeDepSetting = (usDllCharacteristics == DEP_DISABLED || usDllCharacteristics == DEP_ENABLED);
  353.  
  354.     if (bCanChangeDepSetting)
  355.     {
  356.         ushort usDllCharacteristicsRequired = (mode == PATCH_SET_ON) ? DEP_ENABLED : DEP_DISABLED;
  357.         if (usDllCharacteristics != usDllCharacteristicsRequired)
  358.         {
  359.             // Change needed!
  360.             if (!WriteFileValue(strGTAEXEPath, usDllCharacteristicsRequired, fileOffsets.DllCharacteristics))
  361.             {
  362.                 return PATCH_SET_RESULT_REQ_ADMIN;
  363.             }
  364.         }
  365.     }
  366.     return PATCH_SET_RESULT_OK;
  367. }
  368.  
  369. //////////////////////////////////////////////////////////
  370. //
  371. // UpdatePatchStatusNvightmare
  372. //
  373. // Change the PE header to export 'NvOptimusEnablement'
  374. //
  375. //////////////////////////////////////////////////////////
  376. namespace
  377. {
  378.     #define EU_VERSION_BYTE 0x004A1AA0     // Zero if US version
  379.  
  380.     uint oldExportDir[] = {0, 0};
  381.     uint newExportDir[] = {0x004a32d0, 0x00000060};
  382.     uint oldExportTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  383.     uint newExportTable[] = {0x00000000, 0x51a9df70, 0x00000000, 0x004a3302,             //  ....pߩQ.....3J.
  384.                              0x00000001, 0x00000001, 0x00000001, 0x004a32f8,             //  ............<F8>2J.
  385.                              0x004a32fc, 0x004a3300, 0x004c6988, 0x004a3317,             //  <FC>/<A3>..3J.<88>iL..3J.
  386.                              0x74670000, 0x61735f61, 0x6578652e, 0x00000000,             //  ..gta_sa.exe....
  387.                              0x00000000, 0x4e000000, 0x74704f76, 0x73756d69,             //  .......NvOptimus
  388.                              0x62616e45, 0x656d656c, 0x0000746e, 0x00000000};            //  Enablement......
  389.  
  390.     static_assert(sizeof(oldExportDir) == sizeof(newExportDir), "Invalid export dir size");
  391.     static_assert(sizeof(oldExportTable) == sizeof(newExportTable), "Invalid export table size");
  392.  
  393.     struct SDataumRow
  394.     {
  395.         uint  uiFileOffsetUS;
  396.         uint  uiFileOffsetEU;
  397.         void* pOldData;
  398.         void* pNewData;
  399.         uint  uiDataSize;
  400.     };
  401.  
  402.     // List of patchlets
  403.     SDataumRow datumList[] = {
  404.         {
  405.             0x004A1AD0,
  406.             0x004A1ED0,
  407.             oldExportTable,
  408.             newExportTable,
  409.             sizeof(newExportTable),
  410.         },
  411.         {
  412.             0x000000F8,
  413.             0x000000F8,
  414.             oldExportDir,
  415.             newExportDir,
  416.             sizeof(newExportDir),
  417.         },
  418.     };
  419.  
  420.     SDataumRow valueItem = {0x004C4588, 0x004C4988, NULL, NULL, 0};
  421. }            // namespace
  422.  
  423. EPatchResult UpdatePatchStatusNvightmare(const SString& strGTAEXEPath, EPatchMode mode)
  424. {
  425.     char  bIsEUVersion = false;
  426.     bool  bHasExportTable = true;
  427.     uint  uiExportValue = 0;
  428.     bool  bUnknownBytes = false;
  429.     FILE* fh = File::Fopen(strGTAEXEPath, "rb");
  430.     bool  bFileError = (fh == NULL);
  431.     if (!bFileError)
  432.     {
  433.         // Determine version
  434.         bFileError |= (fseek(fh, EU_VERSION_BYTE, SEEK_SET) != 0);
  435.         bFileError |= (fread(&bIsEUVersion, 1, 1, fh) != 1);
  436.  
  437.         // Determine patched status
  438.         for (uint i = 0; i < NUMELMS(datumList); i++)
  439.         {
  440.             const SDataumRow& row = datumList[i];
  441.             uint              uiFileOffset = bIsEUVersion ? row.uiFileOffsetEU : row.uiFileOffsetUS;
  442.  
  443.             bFileError |= (fseek(fh, uiFileOffset, SEEK_SET) != 0);
  444.  
  445.             std::vector<char> buffer(row.uiDataSize);
  446.             bFileError |= (fread(&buffer[0], row.uiDataSize, 1, fh) != 1);
  447.  
  448.             if (memcmp(&buffer[0], row.pOldData, row.uiDataSize) == 0)
  449.                 bHasExportTable = false;
  450.             else if (memcmp(&buffer[0], row.pNewData, row.uiDataSize) != 0)
  451.                 bUnknownBytes = true;
  452.         }
  453.         // Determine export value
  454.         {
  455.             uint uiFileOffset = bIsEUVersion ? valueItem.uiFileOffsetEU : valueItem.uiFileOffsetUS;
  456.             bFileError |= (fseek(fh, uiFileOffset, SEEK_SET) != 0);
  457.             bFileError |= (fread(&uiExportValue, sizeof(uiExportValue), 1, fh) != 1);
  458.         }
  459.         fclose(fh);
  460.     }
  461.  
  462.     // Return status if just checking
  463.     if (mode == PATCH_CHECK)
  464.     {
  465.         if (bHasExportTable && uiExportValue == 1)
  466.             return PATCH_CHECK_RESULT_ON;
  467.         return PATCH_CHECK_RESULT_OFF;
  468.     }
  469.  
  470.     if (bFileError)
  471.         WriteDebugEventAndReport(9801, "Nvightmare patch: Can not apply due to unknown file error");
  472.     else if (bUnknownBytes)
  473.         WriteDebugEventAndReport(9802, "Nvightmare patch: Can not apply due to unknown file bytes");
  474.     else
  475.     {
  476.         // Determine if change required
  477.         bool bReqExportTable = (mode == PATCH_SET_ON);
  478.         uint uiReqExportValue = 1;
  479.         if (bReqExportTable == bHasExportTable && uiReqExportValue == uiExportValue)
  480.         {
  481.             if (bReqExportTable)
  482.                 WriteDebugEvent(SString("Nvightmare patch:  Already applied ExportValue of %d", uiReqExportValue));
  483.         }
  484.         else
  485.         {
  486.             // Change needed!
  487.             SetFileAttributes(strGTAEXEPath, FILE_ATTRIBUTE_NORMAL);
  488.             FILE* fh = File::Fopen(strGTAEXEPath, "r+b");
  489.             if (!fh)
  490.             {
  491.                 return PATCH_SET_RESULT_REQ_ADMIN;
  492.             }
  493.  
  494.             bool bFileError = false;
  495.             // Write patches
  496.             if (bReqExportTable != bHasExportTable)
  497.             {
  498.                 WriteDebugEvent(SString("Nvightmare patch: Changing HasExportTable to %d", bReqExportTable));
  499.                 for (uint i = 0; i < NUMELMS(datumList); i++)
  500.                 {
  501.                     const SDataumRow& row = datumList[i];
  502.                     uint              uiFileOffset = bIsEUVersion ? row.uiFileOffsetEU : row.uiFileOffsetUS;
  503.  
  504.                     bFileError |= (fseek(fh, uiFileOffset, SEEK_SET) != 0);
  505.                     if (bReqExportTable)
  506.                         bFileError |= (fwrite(row.pNewData, row.uiDataSize, 1, fh) != 1);
  507.                     else
  508.                         bFileError |= (fwrite(row.pOldData, row.uiDataSize, 1, fh) != 1);
  509.                 }
  510.             }
  511.             // Write value
  512.             if (uiReqExportValue != uiExportValue)
  513.             {
  514.                 WriteDebugEvent(SString("Nvightmare patch: Changing ExportValue to %d", uiReqExportValue));
  515.                 uint uiFileOffset = bIsEUVersion ? valueItem.uiFileOffsetEU : valueItem.uiFileOffsetUS;
  516.                 bFileError |= (fseek(fh, uiFileOffset, SEEK_SET) != 0);
  517.                 bFileError |= (fwrite(&uiReqExportValue, sizeof(uiReqExportValue), 1, fh) != 1);
  518.             }
  519.  
  520.             fclose(fh);
  521.             if (bFileError)
  522.                 WriteDebugEventAndReport(9803, "Nvightmare patch: File update completed with file errors");
  523.             else
  524.                 WriteDebugEvent("Nvightmare patch: File update completed");
  525.         }
  526.     }
  527.     return PATCH_SET_RESULT_OK;
  528. }
  529.  
  530. //////////////////////////////////////////////////////////
  531. //
  532. // GetPatchRequirementAltModules
  533. //
  534. // Return true if checksum for some dlls will cause problems
  535. //
  536. //////////////////////////////////////////////////////////
  537. bool GetPatchRequirementAltModules()
  538. {
  539.     // Only do file check once per launch
  540.     static bool bDone = false;
  541.     static bool bMismatch = false;
  542.  
  543.     if (!bDone)
  544.     {
  545.         SString strGTAPath = GetGTAPath();
  546.         if (!strGTAPath.empty())
  547.         {
  548.             struct
  549.             {
  550.                 const char* szMd5;
  551.                 const char* szFilename;
  552.             } fileList[] = {{"309D860FC8137E5FE9E7056C33B4B8BE", "eax.dll"},
  553.                             {"0602F672BA595716E64EC4040E6DE376", "ogg.dll"},
  554.                             {"2840F08DD9753A5B13C60D6D1C165C9A", "vorbis.dll"},
  555.                             {"2B7B803311D2B228F065C45D13E1AEB2", "vorbisfile.dll"}};
  556.  
  557.             for (uint i = 0; i < NUMELMS(fileList); i++)
  558.             {
  559.                 SString strPathFilename = PathJoin(strGTAPath, fileList[i].szFilename);
  560.                 SString strMd5 = CMD5Hasher::CalculateHexString(strPathFilename);
  561.                 if (strMd5.CompareI(fileList[i].szMd5) == false)
  562.                     bMismatch = true;
  563.             }
  564.         }
  565.         bDone = true;
  566.  
  567.         if (bMismatch)
  568.             WriteDebugEvent("PatchRequirementAltModules: Need to use alt modules");
  569.     }
  570.     return bMismatch;
  571. }
  572.  
  573. //////////////////////////////////////////////////////////
  574. //
  575. // UpdatePatchStatusAltModules
  576. //
  577. // Change dll list to use different files
  578. //
  579. //////////////////////////////////////////////////////////
  580. struct SSearchInfo
  581. {
  582.     uint        uiOffsetStart;
  583.     uint        uiSearchSize;
  584.     const char* szOldName;
  585.     const char* szNewName;
  586.     uint        uiFileOffset;
  587. };
  588.  
  589. bool SearchPredicate(char a, char b)
  590. {
  591.     return (tolower(a) == tolower(b));
  592. }
  593.  
  594. EPatchResult UpdatePatchStatusAltModules(const SString& strGTAEXEPath, EPatchMode mode)
  595. {
  596.     // List of names to check/change
  597.     SSearchInfo searchList[] = {
  598.         {
  599.             0x4a0000,
  600.             0x3000,
  601.             "vorbisfile.dll",
  602.             "vvof.dll",
  603.             0,
  604.         },
  605.         {
  606.             0x4a0000,
  607.             0x3000,
  608.             "eax.dll",
  609.             "vea.dll",
  610.             0,
  611.         },
  612.         {
  613.             0xD96000,
  614.             0x7000,
  615.             "vorbisfile.dll",
  616.             "vvof.dll",
  617.             0,
  618.         },
  619.         {
  620.             0xD96000,
  621.             0x7000,
  622.             "eax.dll",
  623.             "vea.dll",
  624.             0,
  625.         },
  626.     };
  627.  
  628.     uint uiNumOldNames = 0;
  629.     uint uiNumNewNames = 0;
  630.  
  631.     FILE* fh = File::Fopen(strGTAEXEPath, "rb");
  632.     if (fh)
  633.     {
  634.         for (uint i = 0; i < NUMELMS(searchList); i++)
  635.         {
  636.             SSearchInfo& item = searchList[i];
  637.             if (!fseek(fh, item.uiOffsetStart, SEEK_SET))
  638.             {
  639.                 std::vector<char> buffer;
  640.                 buffer.resize(item.uiSearchSize);
  641.                 if (fread(&buffer[0], item.uiSearchSize, 1, fh) == 1)
  642.                 {
  643.                     std::vector<char>::iterator it;
  644.                     it = std::search(buffer.begin(), buffer.end(), item.szOldName, item.szOldName + strlen(item.szOldName), SearchPredicate);
  645.                     if (it != buffer.end())
  646.                     {
  647.                         uiNumOldNames++;
  648.                     }
  649.                     else
  650.                     {
  651.                         it = std::search(buffer.begin(), buffer.end(), item.szNewName, item.szNewName + strlen(item.szNewName), SearchPredicate);
  652.                         if (it != buffer.end())
  653.                         {
  654.                             uiNumNewNames++;
  655.                         }
  656.                     }
  657.  
  658.                     if (it != buffer.end())
  659.                     {
  660.                         char* p0 = &buffer[0];
  661.                         char* p1 = &(*it);
  662.                         item.uiFileOffset = item.uiOffsetStart + (uint)p1 - (uint)p0;
  663.                     }
  664.                 }
  665.             }
  666.         }
  667.         fclose(fh);
  668.     }
  669.  
  670.     // Return status if just checking
  671.     if (mode == PATCH_CHECK)
  672.     {
  673.         if (uiNumNewNames > 0)
  674.             return PATCH_CHECK_RESULT_ON;
  675.         return PATCH_CHECK_RESULT_OFF;
  676.     }
  677.  
  678.     if (uiNumOldNames + uiNumNewNames != 4)
  679.     {
  680.         WriteDebugEventAndReport(9804, SString("UpdatePatchStatusAltModules: Can't find module names (%d,%d)", uiNumOldNames, uiNumNewNames));
  681.     }
  682.  
  683.     if ((mode == PATCH_SET_ON && uiNumOldNames > 0) || (mode == PATCH_SET_OFF && uiNumNewNames > 0))
  684.     {
  685.         // Change needed!
  686.  
  687.         // Can't do this to gta_sa.exe 4 sure
  688.         assert(!strGTAEXEPath.EndsWithI("gta_sa.exe"));
  689.  
  690.         SetFileAttributes(strGTAEXEPath, FILE_ATTRIBUTE_NORMAL);
  691.         FILE* fh = File::Fopen(strGTAEXEPath, "r+b");
  692.         if (!fh)
  693.         {
  694.             return PATCH_SET_RESULT_REQ_ADMIN;
  695.         }
  696.  
  697.         for (uint i = 0; i < NUMELMS(searchList); i++)
  698.         {
  699.             SSearchInfo& item = searchList[i];
  700.             const char*  szName = (mode == PATCH_SET_ON) ? item.szNewName : item.szOldName;
  701.  
  702.             if (item.uiFileOffset)
  703.             {
  704.                 if (!fseek(fh, item.uiFileOffset, SEEK_SET))
  705.                 {
  706.                     fwrite(szName, strlen(szName) + 1, 1, fh);
  707.                 }
  708.             }
  709.         }
  710.         fclose(fh);
  711.  
  712.         if (mode == PATCH_SET_ON)
  713.             WriteDebugEvent(SString("UpdatePatchStatusAltModules: Now using alt modules (%d,%d)", uiNumOldNames, uiNumNewNames));
  714.     }
  715.  
  716.     return PATCH_SET_RESULT_OK;
  717. }
  718.  
  719. //////////////////////////////////////////////////////////
  720. //
  721. // UpdatePatchStatusEntryPoint
  722. //
  723. // Fix AddressOfEntryPoint incase of corruption
  724. //
  725. //////////////////////////////////////////////////////////
  726. EPatchResult UpdatePatchStatusEntryPoint(const SString& strGTAEXEPath, EPatchMode mode)
  727. {
  728.     SPEFileOffsets fileOffsets;
  729.     GetPEFileOffsets(fileOffsets, strGTAEXEPath);
  730.  
  731.     // Get address from the file
  732.     uint uiCurrentEntryPoint = 0;
  733.     ReadFileValue(strGTAEXEPath, uiCurrentEntryPoint, fileOffsets.AddressOfEntryPoint);
  734.  
  735.     // Calc required address
  736.     std::map<EGtaFileVersion, uint> versionEntryPoints = {
  737.         {EGtaFileVersion::US, 0x0424570}, {EGtaFileVersion::EU, 0x04245B0}, {EGtaFileVersion::Encrypted, 0x0EFFE40}};
  738.     uint uiRequiredEntryPoint = MapFindRef(versionEntryPoints, GetGtaFileVersion(strGTAEXEPath));
  739.  
  740.     if (mode == PATCH_CHECK)
  741.     {
  742.         if (uiCurrentEntryPoint == uiRequiredEntryPoint)
  743.             return PATCH_CHECK_RESULT_ON;
  744.         return PATCH_CHECK_RESULT_OFF;
  745.     }
  746.  
  747.     // Check it's a value that should be fixed
  748.     bool bCanChangeEntryPoint = (uiCurrentEntryPoint > 0x1170000) || (uiCurrentEntryPoint == uiRequiredEntryPoint);
  749.     if (bCanChangeEntryPoint)
  750.     {
  751.         if (mode == PATCH_SET_ON && uiCurrentEntryPoint != uiRequiredEntryPoint)
  752.         {
  753.             // Change needed! Can't do this to gta_sa.exe
  754.             assert(!strGTAEXEPath.EndsWithI("gta_sa.exe"));
  755.             if (!WriteFileValue(strGTAEXEPath, uiRequiredEntryPoint, fileOffsets.AddressOfEntryPoint))
  756.             {
  757.                 return PATCH_SET_RESULT_REQ_ADMIN;
  758.             }
  759.         }
  760.     }
  761.     else
  762.     {
  763.         WriteDebugEventAndReport(
  764.             9806, SString("Unable to set AddressOfEntryPoint [FilePosition=0x%x EntryPoint=0x%x]", fileOffsets.AddressOfEntryPoint, uiCurrentEntryPoint));
  765.     }
  766.     return PATCH_SET_RESULT_OK;
  767. }
  768.  
  769. //////////////////////////////////////////////////////////
  770. //
  771. // GetPatchRequirementEntryPoint
  772. //
  773. // Return true if AddressOfEntryPoint in gta_sa.exe should be fixed (in proxy_sa.exe)
  774. //
  775. //////////////////////////////////////////////////////////
  776. bool GetPatchRequirementEntryPoint()
  777. {
  778.     // Only do file check once per launch
  779.     static bool bDone = false;
  780.     static bool bMismatch = false;
  781.  
  782.     if (!bDone)
  783.     {
  784.         SString strGTAExePath = GetExePathFilename(false);
  785.         if (!strGTAExePath.empty())
  786.         {
  787.             bMismatch = (UpdatePatchStatusEntryPoint(strGTAExePath, PATCH_CHECK) == PATCH_CHECK_RESULT_OFF);
  788.         }
  789.         bDone = true;
  790.  
  791.         if (bMismatch)
  792.             WriteDebugEvent("PatchRequirementEntryPoint: Need to change entry point");
  793.     }
  794.     return bMismatch;
  795. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top