normalize spacing ;-;
This commit is contained in:
parent
d1493f1182
commit
48262dbae3
|
|
@ -5,23 +5,23 @@
|
||||||
|
|
||||||
struct Tuple
|
struct Tuple
|
||||||
{
|
{
|
||||||
void* padding1[4];
|
void* padding1[4];
|
||||||
bool padding2;
|
bool padding2;
|
||||||
bool padding3;
|
bool padding3;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DataModel
|
struct DataModel
|
||||||
{
|
{
|
||||||
void* padding1[CLASSPADDING_DATAMODEL__JOBID + PADDING_STRUCT];
|
void* padding1[CLASSPADDING_DATAMODEL__JOBID + PADDING_STRUCT];
|
||||||
std::string jobId;
|
std::string jobId;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Game
|
struct Game
|
||||||
{
|
{
|
||||||
// 2010 has a class size of 104 bytes
|
// 2010 has a class size of 104 bytes
|
||||||
void* padding1[8];
|
void* padding1[8];
|
||||||
std::shared_ptr<DataModel> dataModel;
|
std::shared_ptr<DataModel> dataModel;
|
||||||
void* padding2[9];
|
void* padding2[9];
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto Game__initializeClass = (Game * (__thiscall*)(Game* _this, int a2))0x455D40;
|
const auto Game__initializeClass = (Game * (__thiscall*)(Game* _this, int a2))0x455D40;
|
||||||
|
|
@ -34,21 +34,21 @@ const auto ScriptContext__execute = (void (__thiscall*)(void* _this, int identit
|
||||||
struct Http
|
struct Http
|
||||||
{
|
{
|
||||||
#if PADDING_STRUCT != 0
|
#if PADDING_STRUCT != 0
|
||||||
void* padding1[1];
|
void* padding1[1];
|
||||||
#endif
|
#endif
|
||||||
std::string alternateUrl;
|
std::string alternateUrl;
|
||||||
void* padding2[3 + PADDING_STRUCT];
|
void* padding2[3 + PADDING_STRUCT];
|
||||||
std::string url;
|
std::string url;
|
||||||
};
|
};
|
||||||
|
|
||||||
// const auto DataModel__createDataModel = (std::shared_ptr<void>(__thiscall*)(bool startHeartbeat))ADDRESS_DATAMODEL__CREATEDATAMODEL;
|
// const auto DataModel__createDataModel = (std::shared_ptr<void>(__thiscall*)(bool startHeartbeat))ADDRESS_DATAMODEL__CREATEDATAMODEL;
|
||||||
|
|
||||||
struct Packet
|
struct Packet
|
||||||
{
|
{
|
||||||
void* padding1[7];
|
void* padding1[7];
|
||||||
unsigned int length;
|
unsigned int length;
|
||||||
void* padding2[1];
|
void* padding2[1];
|
||||||
unsigned char* data;
|
unsigned char* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConcurrentRakPeer {};
|
struct ConcurrentRakPeer {};
|
||||||
|
|
@ -56,9 +56,9 @@ struct RakPeerInterface {};
|
||||||
|
|
||||||
struct ServerReplicator
|
struct ServerReplicator
|
||||||
{
|
{
|
||||||
void* padding1[1869]; // offset of 0 -> 7476
|
void* padding1[1869]; // offset of 0 -> 7476
|
||||||
bool padding2; // offset of 7476 -> 7477
|
bool padding2; // offset of 7476 -> 7477
|
||||||
bool isAuthenticated; // offset of 7477 -> 7478
|
bool isAuthenticated; // offset of 7477 -> 7478
|
||||||
};
|
};
|
||||||
|
|
||||||
// 2010 struct definitions:
|
// 2010 struct definitions:
|
||||||
|
|
@ -71,8 +71,8 @@ const auto CWorkspace__ExecUrlScript = (HRESULT(__stdcall*)(CWorkspace * workspa
|
||||||
|
|
||||||
struct CRobloxDoc
|
struct CRobloxDoc
|
||||||
{
|
{
|
||||||
void* padding1[CLASSPADDING_CROBLOXDOC__WORKSPACE];
|
void* padding1[CLASSPADDING_CROBLOXDOC__WORKSPACE];
|
||||||
CWorkspace* workspace;
|
CWorkspace* workspace;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CApp;
|
struct CApp;
|
||||||
|
|
@ -91,8 +91,8 @@ const auto CRobloxApp__CreateDocument = (CRobloxDoc * (__thiscall*)(CRobloxApp *
|
||||||
|
|
||||||
struct CCommandLineInfo
|
struct CCommandLineInfo
|
||||||
{
|
{
|
||||||
void* padding1[3];
|
void* padding1[3];
|
||||||
BOOL m_bRunAutomated;
|
BOOL m_bRunAutomated;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CRobloxCommandLineInfo : public CCommandLineInfo {};
|
class CRobloxCommandLineInfo : public CCommandLineInfo {};
|
||||||
|
|
|
||||||
|
|
@ -110,18 +110,18 @@
|
||||||
// RobloxPlayerBeta (2012)
|
// RobloxPlayerBeta (2012)
|
||||||
#ifdef PLAYER2012
|
#ifdef PLAYER2012
|
||||||
/*
|
/*
|
||||||
2012 is a bit different in that the player executable is protected with
|
2012 is a bit different in that the player executable is protected with
|
||||||
VMProtect. VMProtect offsets the memory locations randomly on startup.
|
VMProtect. VMProtect offsets the memory locations randomly on startup.
|
||||||
This causes address definitions (such as the ones below) to look a bit off.
|
This causes address definitions (such as the ones below) to look a bit off.
|
||||||
|
|
||||||
For example, if the beginning of the program is located at 0x00BF1000 and
|
For example, if the beginning of the program is located at 0x00BF1000 and
|
||||||
you have a TrustCheck hook that is at 0x00DF20A0, VMProtect will offset the
|
you have a TrustCheck hook that is at 0x00DF20A0, VMProtect will offset the
|
||||||
memory location from 0x00000000 - 0x00FF0000. Thus, the 0x00BF0000 in
|
memory location from 0x00000000 - 0x00FF0000. Thus, the 0x00BF0000 in
|
||||||
0x00BF1000 is actually an offset.
|
0x00BF1000 is actually an offset.
|
||||||
|
|
||||||
With that offset, the address you'd have to put for your TrustCheck hook will
|
With that offset, the address you'd have to put for your TrustCheck hook will
|
||||||
be (0x00DF20A0 - 0x00BF0000) = 0x002020A0. Then, you just put that address
|
be (0x00DF20A0 - 0x00BF0000) = 0x002020A0. Then, you just put that address
|
||||||
into the function.
|
into the function.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// MFC specific definitions
|
// MFC specific definitions
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ extern Crypt__verifySignatureBase64_t Crypt__verifySignatureBase64;
|
||||||
|
|
||||||
class Crypt
|
class Crypt
|
||||||
{
|
{
|
||||||
HCRYPTPROV context;
|
HCRYPTPROV context;
|
||||||
HCRYPTKEY key;
|
HCRYPTKEY key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Crypt();
|
Crypt();
|
||||||
~Crypt();
|
~Crypt();
|
||||||
bool verifySignatureBase64(std::string message, std::string signatureBase64, ALG_ID algorithm);
|
bool verifySignatureBase64(std::string message, std::string signatureBase64, ALG_ID algorithm);
|
||||||
};
|
};
|
||||||
|
|
@ -3,194 +3,194 @@
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
|
|
||||||
#define CHECK(condition, code) \
|
#define CHECK(condition, code) \
|
||||||
if(!error) { \
|
if(!error) { \
|
||||||
if ((condition)) { \
|
if ((condition)) { \
|
||||||
error = code; \
|
error = code; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
Http__httpGetPostWinInet_t Http__httpGetPostWinInet = (Http__httpGetPostWinInet_t)ADDRESS_HTTP__HTTPGETPOSTWININET;
|
Http__httpGetPostWinInet_t Http__httpGetPostWinInet = (Http__httpGetPostWinInet_t)ADDRESS_HTTP__HTTPGETPOSTWININET;
|
||||||
Http__trustCheck_t Http__trustCheck = (Http__trustCheck_t)ADDRESS_HTTP__TRUSTCHECK;
|
Http__trustCheck_t Http__trustCheck = (Http__trustCheck_t)ADDRESS_HTTP__TRUSTCHECK;
|
||||||
|
|
||||||
size_t write(char* contents, size_t size, size_t memory, void* pointer)
|
size_t write(char* contents, size_t size, size_t memory, void* pointer)
|
||||||
{
|
{
|
||||||
((std::string*)pointer)->append((char*)contents, size * memory);
|
((std::string*)pointer)->append((char*)contents, size * memory);
|
||||||
return size * memory;
|
return size * memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, int a3, bool compressData, LPCSTR additionalHeaders, int a6)
|
void __fastcall Http__httpGetPostWinInet_hook(Http* _this, void*, bool isPost, int a3, bool compressData, LPCSTR additionalHeaders, int a6)
|
||||||
{
|
{
|
||||||
CURLU* curl = curl_url();
|
CURLU* curl = curl_url();
|
||||||
CURLUcode result = curl_url_set(curl, CURLUPART_URL, _this->url.c_str(), 0);
|
CURLUcode result = curl_url_set(curl, CURLUPART_URL, _this->url.c_str(), 0);
|
||||||
|
|
||||||
Http _changed = *_this;
|
Http _changed = *_this;
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
char* path;
|
char* path;
|
||||||
char* host;
|
char* host;
|
||||||
char* query;
|
char* query;
|
||||||
|
|
||||||
curl_url_get(curl, CURLUPART_PATH, &path, 0);
|
curl_url_get(curl, CURLUPART_PATH, &path, 0);
|
||||||
curl_url_get(curl, CURLUPART_HOST, &host, 0);
|
curl_url_get(curl, CURLUPART_HOST, &host, 0);
|
||||||
curl_url_get(curl, CURLUPART_QUERY, &query, 0);
|
curl_url_get(curl, CURLUPART_QUERY, &query, 0);
|
||||||
curl_url_cleanup(curl);
|
curl_url_cleanup(curl);
|
||||||
|
|
||||||
if (path != NULL && host != NULL && query != NULL)
|
if (path != NULL && host != NULL && query != NULL)
|
||||||
{
|
{
|
||||||
std::string _path = Util::toLower(std::string(path));
|
std::string _path = Util::toLower(std::string(path));
|
||||||
std::string _host = std::string(host);
|
std::string _host = std::string(host);
|
||||||
std::string _query = std::string(query);
|
std::string _query = std::string(query);
|
||||||
|
|
||||||
if (_host == "roblox.com" || _host == "www.roblox.com")
|
if (_host == "roblox.com" || _host == "www.roblox.com")
|
||||||
{
|
{
|
||||||
if (_path == "/asset" || _path == "/asset/" || _path == "/asset/default.ashx")
|
if (_path == "/asset" || _path == "/asset/" || _path == "/asset/default.ashx")
|
||||||
{
|
{
|
||||||
_changed.url = "https://assetdelivery.roblox.com/v1/asset/?" + _query;
|
_changed.url = "https://assetdelivery.roblox.com/v1/asset/?" + _query;
|
||||||
_this = &_changed;
|
_this = &_changed;
|
||||||
}
|
}
|
||||||
else if (_path == "/thumbs/asset.ashx" || _path == "/thumbs/avatar.ashx")
|
else if (_path == "/thumbs/asset.ashx" || _path == "/thumbs/avatar.ashx")
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Both Roblox endpoints require thumbnailFormatId to be set. We will make the default value for it as 0.
|
Both Roblox endpoints require thumbnailFormatId to be set. We will make the default value for it as 0.
|
||||||
|
|
||||||
Asset.ashx -> requires overrideModeration (default false) -> /asset/request-thumbnail-fix
|
Asset.ashx -> requires overrideModeration (default false) -> /asset/request-thumbnail-fix
|
||||||
Avatar.ashx -> requires dummy (default false) -> /avatar/request-thumbnail-fix
|
Avatar.ashx -> requires dummy (default false) -> /avatar/request-thumbnail-fix
|
||||||
|
|
||||||
1. Parse query
|
1. Parse query
|
||||||
2. Construct a brand new blank query with thumbnailFormatId as 0 and dummy/overrideModeration as false (if Avatar.ashx or Asset.ashx)
|
2. Construct a brand new blank query with thumbnailFormatId as 0 and dummy/overrideModeration as false (if Avatar.ashx or Asset.ashx)
|
||||||
3. Merge the old query with priority over the old query so that if they declared any of the special variables, ours gets overwritten
|
3. Merge the old query with priority over the old query so that if they declared any of the special variables, ours gets overwritten
|
||||||
4. Rename id (if found) to assetId or userId (specific to the endpoint)
|
4. Rename id (if found) to assetId or userId (specific to the endpoint)
|
||||||
5. Append to the Roblox url (specific to the endpoint)
|
5. Append to the Roblox url (specific to the endpoint)
|
||||||
6. Fetch Roblox API
|
6. Fetch Roblox API
|
||||||
7. Parse JSON
|
7. Parse JSON
|
||||||
8. Set the URL as the given url
|
8. Set the URL as the given url
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string api = "https://www.roblox.com/" + std::string(_path == "/thumbs/asset.ashx" ? "asset" : "avatar") + "/request-thumbnail-fix";
|
std::string api = "https://www.roblox.com/" + std::string(_path == "/thumbs/asset.ashx" ? "asset" : "avatar") + "/request-thumbnail-fix";
|
||||||
|
|
||||||
std::map<std::string, std::string> source = Util::parseQueryString(query);
|
std::map<std::string, std::string> source = Util::parseQueryString(query);
|
||||||
std::map<std::string, std::string> fixed = {
|
std::map<std::string, std::string> fixed = {
|
||||||
{ _path == "/thumbs/asset.ashx" ? "overrideModeration" : "dummy", "false" },
|
{ _path == "/thumbs/asset.ashx" ? "overrideModeration" : "dummy", "false" },
|
||||||
{ "thumbnailFormatId", "0" }
|
{ "thumbnailFormatId", "0" }
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& pair : source)
|
for (auto& pair : source)
|
||||||
{
|
{
|
||||||
fixed[Util::toLower(pair.first)] = pair.second;
|
fixed[Util::toLower(pair.first)] = pair.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixed.find("id") != fixed.end())
|
if (fixed.find("id") != fixed.end())
|
||||||
{
|
{
|
||||||
auto handler = fixed.extract("id");
|
auto handler = fixed.extract("id");
|
||||||
handler.key() = _path == "/thumbs/asset.ashx" ? "assetId" : "userId";
|
handler.key() = _path == "/thumbs/asset.ashx" ? "assetId" : "userId";
|
||||||
|
|
||||||
fixed.insert(std::move(handler));
|
fixed.insert(std::move(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
api += Util::joinQueryString(fixed);
|
api += Util::joinQueryString(fixed);
|
||||||
|
|
||||||
// get the api response
|
// get the api response
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
long response = 0;
|
long response = 0;
|
||||||
std::string data;
|
std::string data;
|
||||||
|
|
||||||
if (!curl)
|
if (!curl)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to initialize cURL");
|
throw std::runtime_error("Failed to initialize cURL");
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, api);
|
curl_easy_setopt(curl, CURLOPT_URL, api);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
|
||||||
|
|
||||||
result = curl_easy_perform(curl);
|
result = curl_easy_perform(curl);
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
|
||||||
|
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (result != CURLE_OK || response != 200)
|
if (result != CURLE_OK || response != 200)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x1");
|
throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x1");
|
||||||
}
|
}
|
||||||
|
|
||||||
rapidjson::Document document;
|
rapidjson::Document document;
|
||||||
document.Parse(data.c_str());
|
document.Parse(data.c_str());
|
||||||
|
|
||||||
// Ryelow should fucking kill herself
|
// Ryelow should fucking kill herself
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
CHECK(document.HasParseError(), 0x02);
|
CHECK(document.HasParseError(), 0x02);
|
||||||
CHECK(!document.HasMember("d"), 0x03);
|
CHECK(!document.HasMember("d"), 0x03);
|
||||||
CHECK(!document["d"].IsObject(), 0x04);
|
CHECK(!document["d"].IsObject(), 0x04);
|
||||||
CHECK(!document["d"].HasMember("url"), 0x04);
|
CHECK(!document["d"].HasMember("url"), 0x04);
|
||||||
CHECK(!document["d"]["url"].IsString(), 0x04);
|
CHECK(!document["d"]["url"].IsString(), 0x04);
|
||||||
|
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x0" + std::to_string(error));
|
throw std::runtime_error("Unexpected error occurred when fetching Roblox API: 0x0" + std::to_string(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
_changed.url = document["d"]["url"].GetString();
|
_changed.url = document["d"]["url"].GetString();
|
||||||
_this = &_changed;
|
_this = &_changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Http__httpGetPostWinInet(_this, isPost, a3, compressData, additionalHeaders, a6);
|
Http__httpGetPostWinInet(_this, isPost, a3, compressData, additionalHeaders, a6);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL __fastcall Http__trustCheck_hook(const char* url)
|
BOOL __fastcall Http__trustCheck_hook(const char* url)
|
||||||
{
|
{
|
||||||
if (strlen(url) == 7 && !Util::isASCII(url))
|
if (strlen(url) == 7 && !Util::isASCII(url))
|
||||||
{
|
{
|
||||||
// so the client does this really fucking stupid thing where if it opens an ie window,
|
// so the client does this really fucking stupid thing where if it opens an ie window,
|
||||||
// it passes a char**, and not a char*
|
// it passes a char**, and not a char*
|
||||||
// no idea if thats a detours quirk (i doubt it) or if thats how its just actually handled
|
// no idea if thats a detours quirk (i doubt it) or if thats how its just actually handled
|
||||||
// practically no url is ever going to be seven characters long so it doesn't really matter
|
// practically no url is ever going to be seven characters long so it doesn't really matter
|
||||||
|
|
||||||
url = *(char**)url; // wHOEVER DID THIS FUCKING CAST NEEDS TO GET RAPED BY 10 GORILLION GRIGRGERS
|
url = *(char**)url; // wHOEVER DID THIS FUCKING CAST NEEDS TO GET RAPED BY 10 GORILLION GRIGRGERS
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string _url = std::string(url);
|
std::string _url = std::string(url);
|
||||||
|
|
||||||
// checking for embedded schemes must come BEFORE checking if it's valid
|
// checking for embedded schemes must come BEFORE checking if it's valid
|
||||||
// cURL does not treat embedded resources as URLs
|
// cURL does not treat embedded resources as URLs
|
||||||
|
|
||||||
if (_url == "about:blank")
|
if (_url == "about:blank")
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::string allowedEmbeddedScheme : Util::allowedEmbeddedSchemes)
|
for (std::string allowedEmbeddedScheme : Util::allowedEmbeddedSchemes)
|
||||||
{
|
{
|
||||||
if (_url.rfind(allowedEmbeddedScheme + ":", 0) == 0)
|
if (_url.rfind(allowedEmbeddedScheme + ":", 0) == 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLU* curl = curl_url();
|
CURLU* curl = curl_url();
|
||||||
CURLUcode result = curl_url_set(curl, CURLUPART_URL, url, 0);
|
CURLUcode result = curl_url_set(curl, CURLUPART_URL, url, 0);
|
||||||
|
|
||||||
if (result != CURLE_OK)
|
if (result != CURLE_OK)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* scheme;
|
char* scheme;
|
||||||
char* host;
|
char* host;
|
||||||
|
|
||||||
curl_url_get(curl, CURLUPART_SCHEME, &scheme, 0);
|
curl_url_get(curl, CURLUPART_SCHEME, &scheme, 0);
|
||||||
curl_url_get(curl, CURLUPART_HOST, &host, 0);
|
curl_url_get(curl, CURLUPART_HOST, &host, 0);
|
||||||
curl_url_cleanup(curl);
|
curl_url_cleanup(curl);
|
||||||
|
|
||||||
if (std::find(Util::allowedSchemes.begin(), Util::allowedSchemes.end(), std::string(scheme)) != Util::allowedSchemes.end())
|
if (std::find(Util::allowedSchemes.begin(), Util::allowedSchemes.end(), std::string(scheme)) != Util::allowedSchemes.end())
|
||||||
{
|
{
|
||||||
return std::find(Util::allowedHosts.begin(), Util::allowedHosts.end(), std::string(host)) != Util::allowedHosts.end();
|
return std::find(Util::allowedHosts.begin(), Util::allowedHosts.end(), std::string(host)) != Util::allowedHosts.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
namespace Patches
|
namespace Patches
|
||||||
{
|
{
|
||||||
typedef std::pair<void**, void*> Patch;
|
typedef std::pair<void**, void*> Patch;
|
||||||
|
|
||||||
extern std::vector<Patch> patchList;
|
extern std::vector<Patch> patchList;
|
||||||
|
|
||||||
LONG Apply();
|
LONG Apply();
|
||||||
VOID ResolveOffset();
|
VOID ResolveOffset();
|
||||||
INT GetAddressByOffset(int address);
|
INT GetAddressByOffset(int address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define START_PATCH_LIST() std::vector<Patches::Patch> Patches::patchList = {
|
#define START_PATCH_LIST() std::vector<Patches::Patch> Patches::patchList = {
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,11 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
|
||||||
ExitProcess(EXIT_FAILURE);
|
ExitProcess(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
CURLcode result = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
if (result != CURLE_OK)
|
||||||
|
{
|
||||||
|
ExitProcess(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ul_reason_for_call == DLL_PROCESS_DETACH)
|
if (ul_reason_for_call == DLL_PROCESS_DETACH)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue