Skip to content

Commit 8a1a83f

Browse files
authored
Add online licensing checks
1 parent 0b432ac commit 8a1a83f

19 files changed

Lines changed: 314 additions & 192 deletions

UltimateDRM.vcxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216
<GenerateDebugInformation>true</GenerateDebugInformation>
217217
</Link>
218218
<Lib>
219-
<AdditionalDependencies>ntdll.lib;wintrust.lib;crypt32.lib;lib/zlib.lib;lib/libcurl.lib;lib/brotlicommon.lib;lib/brotlidec.lib;lib/brotlienc.lib</AdditionalDependencies>
219+
<AdditionalDependencies>ntdll.lib;wintrust.lib;crypt32.lib;lib/zlib.lib;lib/libcurl.lib;lib/brotlicommon.lib;lib/brotlidec.lib;lib/brotlienc.lib; ws2_32.lib;</AdditionalDependencies>
220220
</Lib>
221221
</ItemDefinitionGroup>
222222
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

include/HttpClient.hpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
#include <vector>
88
#include "Logger.hpp"
99

10-
using namespace std;
11-
1210
struct HttpRequest
1311
{
14-
string url;
15-
vector<string> requestHeaders;
16-
string cookie;
17-
string body;
18-
vector<string> responseHeaders;
19-
string responseText;
12+
std::string url;
13+
std::vector<std::string> requestHeaders;
14+
std::string cookie;
15+
std::string body;
16+
std::vector<std::string> responseHeaders;
17+
std::string responseText;
2018
};
2119

2220
struct MemoryStruct
@@ -26,7 +24,7 @@ struct MemoryStruct
2624

2725
struct ResponseHeaders
2826
{
29-
vector<std::string> headers;
27+
std::vector<std::string> headers;
3028
};
3129

3230
class HttpClient //a simple class for making web/http requests.

include/License.hpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,15 @@ class License final
140140
return LicenseStatus::WrongProduct;
141141

142142
// - plan in allowed set
143-
static const std::unordered_set<std::string> kPlans = { "edu-floating","named-device","site" };
143+
static const std::unordered_set<std::string> kPlans = { "trial", "monthly","ongoing", "infinite" };
144144

145145
if (!kPlans.count(c.plan))
146146
return LicenseStatus::InvalidPlan;
147147

148148
// - seats rule: null for "site", present & >=1 otherwise
149-
if (c.plan == "site")
149+
if (c.plan == "trial")
150150
{
151-
if (c.seats != 0)
151+
if (c.seats != 1)
152152
return LicenseStatus::InvalidSeats;
153153
}
154154
else
@@ -250,7 +250,8 @@ class License final
250250
licenseResult.status = License::LicenseStatus::Expired;
251251
return licenseResult;
252252
}
253-
253+
//iat = 1756694840
254+
//now = 1756683456
254255
if (licenseResult.claims.iat > now + kSkew)
255256
{
256257
licenseResult.status = License::LicenseStatus::ClockSkew;
@@ -274,7 +275,57 @@ class License final
274275
// TODO: look up in your store
275276
return false;
276277
}
278+
};
277279

280+
using json = nlohmann::json;
278281

282+
struct LicenseActivateRequest
283+
{
284+
std::string license_token;
285+
std::string machine_id;
286+
std::string software_version;
279287
};
280288

289+
struct LicenseActivateResponse
290+
{
291+
bool ok;
292+
std::string lease_id;
293+
uint64_t lease_expires_in;
294+
};
295+
296+
static void to_json(json& j, const LicenseActivateRequest& request)
297+
{
298+
j = json{
299+
{"license_token", request.license_token},
300+
{"machine_id", request.machine_id},
301+
{"software_version", request.software_version},
302+
};
303+
}
304+
305+
static inline void from_json(const nlohmann::json& j, LicenseActivateRequest& request)
306+
{
307+
if (j.contains("license_token") && !j["license_token"].is_null())
308+
j["license_token"].get_to(request.license_token);
309+
310+
if (j.contains("machine_id") && !j["machine_id"].is_null())
311+
j["machine_id"].get_to(request.machine_id);
312+
313+
if (j.contains("software_version") && !j["software_version"].is_null())
314+
j["software_version"].get_to(request.software_version);
315+
}
316+
317+
static void to_json(json& j, const LicenseActivateResponse& response)
318+
{
319+
j = json{
320+
{"ok", response.ok},
321+
{"lease_id", response.lease_id},
322+
{"lease_expires_in", response.lease_expires_in},
323+
};
324+
}
325+
326+
static void from_json(const nlohmann::json& j, LicenseActivateResponse& response)
327+
{
328+
j.at("ok").get_to(response.ok);
329+
j.at("lease_id").get_to(response.lease_id);
330+
j.at("lease_expires_in").get_to(response.lease_expires_in);
331+
}

include/LicenseManager.hpp

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010

1111
#pragma comment(lib, "bcrypt.lib")
1212

13-
14-
class LicenseManager final //Not finished yet
13+
class LicenseManager final
1514
{
1615
public:
1716
LicenseManager(std::string LicenseServerEndpoint, bool bAllowOfflineProductUsage, std::string LicenseFileName)
@@ -21,46 +20,62 @@ class LicenseManager final //Not finished yet
2120

2221
~LicenseManager()
2322
{
24-
if (RSAPubKeyPinned != nullptr)
25-
delete[] RSAPubKeyPinned;
23+
if (DEFAULT_PUB_KEY_X != nullptr)
24+
delete[] DEFAULT_PUB_KEY_X;
2625

27-
if (PINNED_PUB_KEY_X != nullptr)
28-
delete[] PINNED_PUB_KEY_X;
26+
if (DEFAULT_PUB_KEY_Y != nullptr)
27+
delete[] DEFAULT_PUB_KEY_Y;
2928

30-
if (PINNED_PUB_KEY_Y != nullptr)
31-
delete[] PINNED_PUB_KEY_Y;
32-
}
29+
if (PublicKeyX != nullptr)
30+
delete[] PublicKeyX;
3331

34-
bool SendLicenseInfo(__in const bool bUsingEncryption);
32+
if (PublicKeyY != nullptr)
33+
delete[] PublicKeyY;
34+
}
3535

36-
static bool Sha256_CNG(const void* data, size_t len, std::vector<uint8_t>& out32);
37-
static bool DerEcdsaToP1363(const uint8_t* der, size_t derLen, uint8_t out64[64]);
36+
bool SendLicenseInfo(__in const bool bUsingEncryption, __in const std::string& machine_id, __in const std::string& software_version, __out std::string& leaseId);
3837

39-
BCRYPT_KEY_HANDLE import_es256_pubkey(__in std::vector<uint8_t>& x, __in std::vector<uint8_t>& y);
4038
bool VerifyLicenseJWT_ES256(__in const std::string& token);
4139

42-
const uint8_t* GetPubX() const { return PINNED_PUB_KEY_X; }
43-
const uint8_t* GetPubY() const { return PINNED_PUB_KEY_Y; }
40+
void SetPubXY(__in const uint8_t* arrX, __in const uint8_t* arrY)
41+
{
42+
if (this->PublicKeyX == nullptr)
43+
this->PublicKeyX = new uint8_t[32]{ 0 };
44+
45+
if (this->PublicKeyY == nullptr)
46+
this->PublicKeyY = new uint8_t[32]{ 0 };
47+
48+
for (int i = 0; i < 32; i++)
49+
{
50+
this->PublicKeyX[i] = arrX[i];
51+
this->PublicKeyY[i] = arrY[i];
52+
}
53+
}
54+
55+
const uint8_t* GetPubX() const { if (this->PublicKeyX == nullptr) return DEFAULT_PUB_KEY_X; else return this->PublicKeyX; }
56+
const uint8_t* GetPubY() const { if (this->PublicKeyY == nullptr) return DEFAULT_PUB_KEY_Y; else return this->PublicKeyY; }
4457

4558
bool IsOfflineUsageAllowed() const { return bAllowOfflineProductUsage; }
4659

60+
void SetLicenseToken(__in const std::string& jwtToken) { this->LicenseToken = jwtToken; }
61+
4762
private:
4863

49-
char* RSAPubKeyPinned = nullptr;
50-
51-
std::string LicenseKey;
52-
std::vector<uint8_t> LicenseSignature; //grabbed from file or registry or w/e
64+
std::string LicenseToken;
5365
std::string LicenseFileName;
54-
5566
std::string LicenseServerEndpoint;
56-
5767
bool bAllowOfflineProductUsage = false;
5868

59-
std::vector<uint8_t> LoadPublicKeyContents(const std::string& pubKeyText);
60-
BCRYPT_KEY_HANDLE LoadRSAPublicKey(const std::vector<uint8_t> derData);
61-
bool VerifySignature(BCRYPT_KEY_HANDLE hKey, const std::vector<uint8_t>& licenseData, const std::vector<uint8_t>& signature);
69+
static bool Sha256_CNG(__in const void* data, __in const size_t len, __out std::vector<uint8_t>& out32);
70+
static bool DerEcdsaToP1363(__in const uint8_t* der, __in const size_t derLen, __out uint8_t out64[64]);
71+
72+
BCRYPT_KEY_HANDLE import_es256_pubkey(__in std::vector<uint8_t>& x, __in std::vector<uint8_t>& y);
73+
74+
uint8_t* PublicKeyX = nullptr; //32 length byte array
75+
uint8_t* PublicKeyY = nullptr; //32 length byte array
6276

63-
//pinned public key -> replace with your public key X/Y from dump_xy.py (we originally generate an ECDSA keypair with openssl, then make a license.jwt file which embeds license details)
64-
const uint8_t* PINNED_PUB_KEY_X = new uint8_t[32] { 0x0e,0x8a,0x31,0x1e,0x93,0x8d,0xc5,0x14,0x8e,0xb7,0x9c,0xb1,0x70,0xd9,0xca,0x35,0x3a,0x44,0x9b,0xb9,0xe1,0x65,0xa0,0xc3,0xfb,0xc6,0xb8,0x73,0x2b,0xd8,0xcd,0xc8 };
65-
const uint8_t* PINNED_PUB_KEY_Y = new uint8_t[32] { 0xfe,0x24,0xf5,0x84,0xeb,0x0e,0x20,0x39,0xd3,0x66,0xbe,0x76,0x14,0x3c,0xdb,0xc0,0xc1,0x97,0xca,0x96,0x83,0x55,0x99,0x0f,0xc1,0x18,0x5b,0x1d,0x7d,0x94,0x48,0x67 };
77+
//pinned DEFAULT public key -> replace with your public key X/Y from running `python dump_xy.py` (we originally generate an ES256 keypair with openssl, then make a license.jwt file which embeds license details)
78+
// If you're just using default license from github, use the fixed key below, otherwise if you use your own license/keys use `SetPublicXY(your_x, your_y)`
79+
const uint8_t* DEFAULT_PUB_KEY_X = new uint8_t[32] { 0x0e,0x8a,0x31,0x1e,0x93,0x8d,0xc5,0x14,0x8e,0xb7,0x9c,0xb1,0x70,0xd9,0xca,0x35,0x3a,0x44,0x9b,0xb9,0xe1,0x65,0xa0,0xc3,0xfb,0xc6,0xb8,0x73,0x2b,0xd8,0xcd,0xc8 };
80+
const uint8_t* DEFAULT_PUB_KEY_Y = new uint8_t[32] { 0xfe,0x24,0xf5,0x84,0xeb,0x0e,0x20,0x39,0xd3,0x66,0xbe,0x76,0x14,0x3c,0xdb,0xc0,0xc1,0x97,0xca,0x96,0x83,0x55,0x99,0x0f,0xc1,0x18,0x5b,0x1d,0x7d,0x94,0x48,0x67 };
6681
};

include/MapProtectedClass.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#include "Definitions.hpp"
55
#include <stdexcept>
66

7-
using namespace std;
8-
97
/*
108
ProtectedMemory - Protects the memory of a class object by memory mapping it, then remapping it with SEC_NO_CHANGE
119
should be used as follows:

include/NAuthenticode.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
#include <wincrypt.h>
66
#include <wintrust.h>
77
#include <mscat.h>
8+
#include <string>
89
#include "Logger.hpp"
910

1011
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
1112

1213
//#pragma comment(lib, "wintrust.lib")
1314
//#pragma comment(lib, "crypt32.lib")
1415

15-
using namespace std;
16-
1716
typedef struct
1817
{
1918
LPWSTR lpszProgramName;
@@ -27,12 +26,12 @@ namespace Authenticode
2726
BOOL VerifyCatalogSignature(__in const LPCWSTR filePath, __in const BOOL checkRevoked);
2827
BOOL HasSignature(__in const LPCWSTR filePath, __in const BOOL checkEndCertRevoked);
2928

30-
wstring GetSignerFromFile(__in const wstring& filePath); //get the 'subject' field of the certifcate (often the company which published the software file)
29+
std::wstring GetSignerFromFile(__in const std::wstring& filePath); //get the 'subject' field of the certifcate (often the company which published the software file)
3130

3231
//https://learn.microsoft.com/en-us/previous-versions/troubleshoot/windows/win32/get-information-authenticode-signed-executables
3332
BOOL GetProgAndPublisherInfo(__in PCMSG_SIGNER_INFO pSignerInfo, __out PSPROG_PUBLISHERINFO Info);
3433
BOOL GetDateOfTimeStamp(__in PCMSG_SIGNER_INFO pSignerInfo, __out SYSTEMTIME* st);
35-
wstring GetCertificateSubject(__in PCCERT_CONTEXT pCertContext);
34+
std::wstring GetCertificateSubject(__in PCCERT_CONTEXT pCertContext);
3635
BOOL GetTimeStampSignerInfo(__in PCMSG_SIGNER_INFO pSignerInfo, __out PCMSG_SIGNER_INFO* pCounterSignerInfo);
3736
LPWSTR AllocateAndCopyWideString(__in LPCWSTR inputString);
3837
}

include/Process.hpp

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212

1313
#pragma comment(lib, "ImageHlp")
1414

15-
using namespace std;
16-
1715
namespace ProcessData
1816
{
1917
typedef enum _PROCESS_INFORMATION_CLASS
@@ -35,15 +33,15 @@ namespace ProcessData
3533

3634
struct MODULE_DATA
3735
{
38-
wstring baseName;
39-
wstring nameWithPath;
36+
std::wstring baseName;
37+
std::wstring nameWithPath;
4038
MODULEINFO dllInfo;
4139
HMODULE hModule;
4240
};
4341

4442
struct Section
4543
{
46-
string name = "";
44+
std::string name;
4745
unsigned int size;
4846
uintptr_t address;
4947

@@ -113,28 +111,28 @@ class Process final
113111

114112
bool FillModuleList();
115113

116-
static list<ProcessData::Section> GetSections(__in const string module);
114+
static std::list<ProcessData::Section> GetSections(__in const std::string& module);
117115

118116
#ifdef _M_IX86
119117
static _MYPEB* GetPEB() { return (_MYPEB*)__readfsdword(0x30); }
120118
#else
121119
static _MYPEB* GetPEB() { return (_MYPEB*)__readgsqword(0x60); }
122120
#endif
123121

124-
static wstring GetProcessName(__in const DWORD pid);
125-
static DWORD GetProcessIdByName(__in const wstring procName);
126-
static list<DWORD> GetProcessIdsByName(__in const wstring procName);
122+
static std::wstring GetProcessName(__in const DWORD pid);
123+
static DWORD GetProcessIdByName(__in const std::wstring& procName);
124+
static std::list<DWORD> GetProcessIdsByName(__in const std::wstring& procName);
127125

128126
static DWORD GetParentProcessId();
129-
static BOOL CheckParentProcess(__in const wstring desiredParent, __in const bool bShouldCheckSignature);
127+
static BOOL CheckParentProcess(__in const std::wstring& desiredParent, __in const bool bShouldCheckSignature);
130128

131-
wstring GetParentName() const { return this->_ParentProcessName; }
129+
std::wstring GetParentName() const { return this->_ParentProcessName; }
132130
uint32_t GetParentId() const { return this->_ParentProcessId; }
133131

134-
void SetParentName(__in const wstring parentName) { this->_ParentProcessName = parentName; }
132+
void SetParentName(__in const std::wstring& parentName) { this->_ParentProcessName = parentName; }
135133
void SetParentId(__in const uint32_t id) { this->_ParentProcessId = id; }
136134

137-
static bool HasExportedFunction(__in const string dllName, __in const string functionName);
135+
static bool HasExportedFunction(__in const std::string& dllName, __in const std::string& functionName);
138136

139137
static FARPROC _GetProcAddress(__in const PCSTR Module, __in const LPCSTR lpProcName); //GetProcAddress without winAPI call
140138

@@ -144,7 +142,7 @@ class Process final
144142

145143
static DWORD GetModuleSize(__in const HMODULE module);
146144

147-
static list<ProcessData::ImportFunction> GetIATEntries(const std::string& module); //start of IAT hook checks
145+
static std::list<ProcessData::ImportFunction> GetIATEntries(const std::string& module); //start of IAT hook checks
148146

149147
static bool IsReturnAddressInModule(__in const uintptr_t RetAddr, __in const wchar_t* module);
150148

@@ -168,14 +166,14 @@ class Process final
168166

169167
uint32_t _ProcessId = 0;
170168

171-
wstring _ProcessName;
172-
wstring _WindowClassName;
173-
wstring _WindowTitle;
169+
std::wstring _ProcessName;
170+
std::wstring _WindowClassName;
171+
std::wstring _WindowTitle;
174172

175-
wstring _ParentProcessName;
173+
std::wstring _ParentProcessName;
176174
uint32_t _ParentProcessId = 0;
177175

178-
list<ProcessData::Section*> MainModuleSections;
176+
std::list<ProcessData::Section*> MainModuleSections;
179177

180-
list<ProcessData::MODULE_DATA*> ModuleList; //todo: make routine to fill this member
178+
std::list<ProcessData::MODULE_DATA*> ModuleList; //todo: make routine to fill this member
181179
};

0 commit comments

Comments
 (0)