Skip to content

Commit f3b0bf1

Browse files
authored
Truly Offline Verification (#18) Thanks @oureveryday
* Offline requests * Offline timestamp
1 parent cf1be9b commit f3b0bf1

File tree

5 files changed

+172
-359
lines changed

5 files changed

+172
-359
lines changed

lol/CMakeLists.txt

-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,4 @@ add_library(dll SHARED dll.cpp)
1111
target_link_libraries(dll minhook)
1212
target_include_directories(dll PRIVATE minhook/src)
1313

14-
add_library(lol SHARED lol.cpp)
15-
target_link_libraries(lol minhook)
16-
target_include_directories(lol PRIVATE minhook/src)
17-
1814
add_subdirectory(minhook)

lol/dll.cpp

+21-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#include <iostream>
88

99
bool fakeResp = false;
10+
void *userData;
11+
typedef size_t (*callback_t)(char *ptr, size_t size, size_t nmemb, void *userdata);
12+
callback_t callback = nullptr;
1013

1114
typedef void (*options_t)(void *, size_t, void *);
1215
options_t oOptions = nullptr;
@@ -18,27 +21,31 @@ void options(void *a1, size_t a2, void *a3) {
1821
}
1922
}
2023

24+
if (a2 == 10001) {
25+
userData = a3;
26+
}
27+
28+
if (a2 == 20011) {
29+
callback = (callback_t)a3;
30+
}
31+
2132
oOptions(a1, a2, a3);
2233
}
2334

24-
typedef size_t (*respHandler_t)(void *, char *, size_t, uint64_t *, uint32_t *a5);
25-
respHandler_t oRespHandler = nullptr;
26-
27-
const auto resp =
35+
const std::string resp =
2836
R"({"msg": "vpJSftgQ2noDAZR3Iri/ForvdhDZvxwlJCXowV9TgKSs+BoMyBMOIuxjpDcMTSov1thaXhg/d9aAKcpxOP6glQ3bSd8bHIGMku3Ck/33VdYhtzx4HwC4Lel5mVGZ9+2jffsIgHyIwxMl+8kYwh/QGQRlkC8zFfyNaMszsZiOxIJCy/RMYfI3buvCDPH/4D1/VxysPnaX+QtrVrs7Bt74byqnd38bi0GhpllEWL7CO+7fI+vMe2OSv6s0CUaOqzhDC5N8wIkHsthyVyP+GYoltTov3Bu5iaxmgZc/eYQPTkTWQ759pIVNjKJwnQI3EtOEdrRog6LAkA/CMGwMwBkScvY508Z3KhnNqqIIF9RpYLI6rdST+o2t5gIK4sElQg/2wHZT6wSm23t7YdxnwzEFZysv/H0y63iI4NMUmyZIkRvCyxlWVMpTt/rV9qubdbCjGDxG7A/0LbxCJBfBgEWu4Krpp1S+hk4qgIB+2apCh5sxU76mLzQdFLzNrgmbQADapyDO6rWw777F9FKlo/r9II8kISi/+2FxXp7TZE3ALbcyUo7zKucahsq7u9ucENm64D3PKV4YZCHchQY7xyYI4DaC1PQzleJxGaGbCoBQ0PZK7f33d3N3qB10OaEfe2de4uTcOKbVAjtjSLrlZcMGiZd40Bho76xCtcgAKG2FDxbH/PJo4BoIYwqiDzqpmxXBOsn0JqKLGLaAyU840GAgyLO62lE7/A26w+B9q7hkOIcKlfXZpdwjsll/dADe2U/uF5nrLxEOUGDx9gbUoB95KLD1S3KCCyaLuv8j4imt2E9EgDzk/1XdIwnbPGAECajV5z4yTpMuyD9XBhmJQIFutw==", "code": 200})";
29-
const auto chunkLength = std::format("{:x}", strlen(resp));
30-
const auto firstChunk = std::format("{}\r\n{}\r\n", chunkLength, resp);
31-
const auto secondChunk = std::format("0\r\n\r\n");
32-
const auto aggregated = firstChunk + secondChunk;
3337

34-
size_t respHandler(void *a1, char *content, size_t length, uint64_t *a4, uint32_t *a5) {
38+
typedef size_t (*perform_t)(void *);
39+
perform_t oPerform = nullptr;
40+
size_t perform(void *a1) {
3541
if (fakeResp == true) {
3642
fakeResp = false;
37-
memcpy(content, aggregated.c_str(), aggregated.size() + 1);
38-
length = aggregated.size();
43+
std::cout << "Faking result" << std::endl;
44+
callback((char *)resp.c_str(), resp.size(), 1, userData);
45+
return 0;
3946
}
4047

41-
return oRespHandler(a1, content, length, a4, a5);
48+
return oPerform(a1);
4249
}
4350

4451
void start() {
@@ -91,10 +98,10 @@ void start() {
9198
}
9299

93100
{
94-
const void *found = Sig::find(base, expectedRegion, "48 89 5C 24 20 56 57 41 54 41 55 41 56 48 83 EC 20");
101+
const void *found = Sig::find(base, expectedRegion, "40 55 56 48 83 EC 38 48 8B F1 48 85 C9 75 0A 8D");
95102

96103
if (found != nullptr) {
97-
MH_CreateHook((LPVOID)found, (LPVOID)respHandler, (LPVOID *)&oRespHandler);
104+
MH_CreateHook((LPVOID)found, perform, (LPVOID *)&oPerform);
98105
MH_EnableHook((LPVOID)found);
99106
}
100107
}

lol/exe.cpp

+149-42
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
#include <filesystem>
66
#include <format>
77
#include <iostream>
8+
#include <thread>
89

910
#include "MinHook.h"
1011
#include "Sig.hpp"
1112

12-
typedef char** (*hwid_t)(char **);
13+
typedef char **(*hwid_t)(char **);
1314
hwid_t oHwid = nullptr;
1415
char **hwid(char **hwid_out) {
1516
auto result = oHwid(hwid_out);
@@ -19,6 +20,11 @@ char **hwid(char **hwid_out) {
1920
}
2021

2122
bool fakeResp = false;
23+
bool fakeVer = false;
24+
25+
void *userData;
26+
typedef size_t (*callback_t)(char *ptr, size_t size, size_t nmemb, void *userdata);
27+
callback_t callback = nullptr;
2228

2329
typedef void (*options_t)(void *, size_t, void *);
2430
options_t oOptions = nullptr;
@@ -28,31 +34,86 @@ void options(void *a1, size_t a2, void *a3) {
2834
if (memcmp(a3, "https://md5c.", 13) == 0) {
2935
fakeResp = true;
3036
}
37+
38+
if (memcmp(a3, "https://ghp.", 12) == 0) {
39+
fakeVer = true;
40+
}
41+
}
42+
43+
if (a2 == 10001) {
44+
userData = a3;
45+
}
46+
47+
if (a2 == 20011) {
48+
callback = (callback_t)a3;
3149
}
3250

3351
oOptions(a1, a2, a3);
3452
}
3553

36-
typedef size_t (*respHandler_t)(void *, char *, size_t, uint64_t *, uint32_t *a5);
37-
respHandler_t oRespHandler = nullptr;
38-
const auto resp =
54+
const std::string versionResp = R"|({
55+
"msg": "success",
56+
"code": 200,
57+
"data": {
58+
"latest_version": "1.3.2.0",
59+
"update_required": true,
60+
"update_url": "https://github.com/Cotton-Buds/calculator/releases",
61+
"announcement": "4.7 os&cn",
62+
"updated_by": "Strigger(main) & Micah(auth) & EtoShinya(tech)",
63+
"updated_at": "2024-06-13 00:21",
64+
"update_diff": {
65+
"added_features": [
66+
"fix all 409",
67+
"Fix camera issues"
68+
],
69+
"deleted_features": [
70+
"修复所有失效功能",
71+
"Restore all malfunctioning features."
72+
],
73+
"total_size": "124 MB"
74+
},
75+
"compatible_versions": [
76+
"none"
77+
]
78+
},
79+
"sign2": "CCDPv7klKvXwkImpFaE+WfSJxrijj4nKHH5sSOQke2rdEpd+jCkiPMU24HCulrEtEfBQEUF2H7vBAQCbb5C8za5//+b77ccfumA63fFuie9WbeLhAIyq6t+UGpu5Ecfh6iLSNyPFZANTyjs3Cn5uXoiBPKgbczCMVN2fy80uUgVqaGYznWlD6zJYla/oPmuAewnd4AHv0kidNUPu9JQI2d++9+Un+GKbsKveN2LjEsc+SdCUtHCadMuJXcMx8lMCfUkORy6q7md2HcvNBc5EZQHQ+xvBy4GHa6qYs6pOfpdZP25ixuiaYtuLyf9572Fg1R3HS3lueFbhAyKDFvn4VA=="
80+
})|";
81+
const std::string resp =
3982
R"({"msg": "vpJSftgQ2noDAZR3Iri/ForvdhDZvxwlJCXowV9TgKSs+BoMyBMOIuxjpDcMTSov1thaXhg/d9aAKcpxOP6glQ3bSd8bHIGMku3Ck/33VdYhtzx4HwC4Lel5mVGZ9+2jffsIgHyIwxMl+8kYwh/QGQRlkC8zFfyNaMszsZiOxIJCy/RMYfI3buvCDPH/4D1/VxysPnaX+QtrVrs7Bt74byqnd38bi0GhpllEWL7CO+7fI+vMe2OSv6s0CUaOqzhDC5N8wIkHsthyVyP+GYoltTov3Bu5iaxmgZc/eYQPTkTWQ759pIVNjKJwnQI3EtOEdrRog6LAkA/CMGwMwBkScvY508Z3KhnNqqIIF9RpYLI6rdST+o2t5gIK4sElQg/2wHZT6wSm23t7YdxnwzEFZysv/H0y63iI4NMUmyZIkRvCyxlWVMpTt/rV9qubdbCjGDxG7A/0LbxCJBfBgEWu4Krpp1S+hk4qgIB+2apCh5sxU76mLzQdFLzNrgmbQADapyDO6rWw777F9FKlo/r9II8kISi/+2FxXp7TZE3ALbcyUo7zKucahsq7u9ucENm64D3PKV4YZCHchQY7xyYI4DaC1PQzleJxGaGbCoBQ0PZK7f33d3N3qB10OaEfe2de4uTcOKbVAjtjSLrlZcMGiZd40Bho76xCtcgAKG2FDxbH/PJo4BoIYwqiDzqpmxXBOsn0JqKLGLaAyU840GAgyLO62lE7/A26w+B9q7hkOIcKlfXZpdwjsll/dADe2U/uF5nrLxEOUGDx9gbUoB95KLD1S3KCCyaLuv8j4imt2E9EgDzk/1XdIwnbPGAECajV5z4yTpMuyD9XBhmJQIFutw==", "code": 200})";
40-
const auto chunkLength = std::format("{:x}", strlen(resp));
41-
const auto firstChunk = std::format("{}\r\n{}\r\n", chunkLength, resp);
42-
const auto secondChunk = std::format("0\r\n\r\n");
43-
const auto aggregated = firstChunk + secondChunk;
4483

4584
bool doneMagic = false;
4685

47-
size_t respHandler(void *a1, char *content, size_t length, uint64_t *a4, uint32_t *a5) {
48-
if (fakeResp == true) {
86+
typedef size_t (*perform_t)(void *);
87+
perform_t oPerform = nullptr;
88+
size_t perform(void *a1) {
89+
if (fakeVer == true) {
90+
fakeVer = false;
91+
callback((char *)versionResp.c_str(), versionResp.size(), 1, userData);
92+
return 0;
93+
} else if (fakeResp == true) {
4994
fakeResp = false;
50-
memcpy(content, aggregated.c_str(), aggregated.size() + 1);
51-
length = aggregated.size();
95+
callback((char *)resp.c_str(), resp.size(), 1, userData);
5296
doneMagic = true;
97+
return 0;
5398
}
5499

55-
return oRespHandler(a1, content, length, a4, a5);
100+
return oPerform(a1);
101+
}
102+
103+
int connectWrite() { return 1; }
104+
105+
const std::string readResponse =
106+
R"(HTTP/1.1 200 OK
107+
Content-Length: 64
108+
Connection: close
109+
110+
{"api":"time","code":"1","currentTime": 1718762445577,"msg":""})";
111+
size_t readIdx = 0;
112+
int read(void *a1, void *buf, int numBytes) {
113+
const auto ret = readResponse.substr(readIdx, numBytes);
114+
memcpy(buf, ret.c_str(), ret.size());
115+
readIdx += ret.size();
116+
return ret.size();
56117
}
57118

58119
typedef HANDLE(WINAPI *CreateRemoteThreadEx_t)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID,
@@ -98,26 +159,7 @@ HANDLE WINAPI createThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttrib
98159
dwCreationFlags, lpAttributeList, lpThreadId);
99160
}
100161

101-
void start() {
102-
const auto ntdll = GetModuleHandle(L"ntdll.dll");
103-
uint8_t callcode = ((uint8_t *)GetProcAddress(ntdll, "NtQuerySection"))[4] - 1;
104-
uint8_t restore[] = {0x4C, 0x8B, 0xD1, 0xB8, callcode};
105-
106-
volatile auto ntProtectVirtualMemory = (uint8_t *)GetProcAddress(ntdll, "NtProtectVirtualMemory");
107-
108-
while (true) {
109-
if (ntProtectVirtualMemory[0] != 0x4C) {
110-
DWORD oldProtect;
111-
VirtualProtect((LPVOID)ntProtectVirtualMemory, sizeof(restore), PAGE_EXECUTE_READWRITE, &oldProtect);
112-
memcpy(ntProtectVirtualMemory, restore, sizeof(restore));
113-
VirtualProtect((LPVOID)ntProtectVirtualMemory, sizeof(restore), oldProtect, nullptr);
114-
115-
break;
116-
}
117-
}
118-
119-
MH_Initialize();
120-
162+
void cont() {
121163
const auto exe = GetModuleHandle(nullptr);
122164
const auto header = (PIMAGE_DOS_HEADER)exe;
123165
const auto nt = (PIMAGE_NT_HEADERS)((uint8_t *)exe + header->e_lfanew);
@@ -142,26 +184,91 @@ void start() {
142184
}
143185

144186
{
145-
const void *found = Sig::find(exe, size, "48 89 5C 24 20 56 57 41 54 41 55 41 56 48 83 EC 20");
187+
const void *found = Sig::find(exe, size, "40 55 56 48 83 EC 38 48 8B F1 48 85 C9 75 0A 8D");
146188

147189
if (found != nullptr) {
148-
MH_CreateHook((LPVOID)found, respHandler, (LPVOID *)&oRespHandler);
190+
MH_CreateHook((LPVOID)found, perform, (LPVOID *)&oPerform);
149191
MH_EnableHook((LPVOID)found);
150192
}
151193
}
152194

153-
while (doneMagic == false) {
154-
Sleep(1);
195+
{
196+
const void *found = Sig::find(exe, size, "40 53 B8 20 00 00 00 E8 64 6F 13 00 48 2B E0 48 83 79 30 00");
197+
198+
if (found != nullptr) {
199+
MH_CreateHook((LPVOID)found, (LPVOID)connectWrite, nullptr);
200+
MH_EnableHook((LPVOID)found);
201+
}
155202
}
156203

157-
MH_DisableHook(MH_ALL_HOOKS);
158-
MH_RemoveHook(MH_ALL_HOOKS);
204+
{
205+
const void *found =
206+
Sig::find(exe, size, "B8 38 00 00 00 E8 96 55 13 00 48 2B E0 45 85 C0 79 2A BA D0 00 00 00");
207+
208+
if (found != nullptr) {
209+
MH_CreateHook((LPVOID)found, (LPVOID)connectWrite, nullptr);
210+
MH_EnableHook((LPVOID)found);
211+
}
212+
}
159213

160214
{
161-
const auto remoteThreadEx = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "CreateRemoteThreadEx");
162-
MH_CreateHook((LPVOID)remoteThreadEx, (LPVOID)createThread, (LPVOID *)&oCreateRemoteThreadEx);
163-
MH_EnableHook((LPVOID)remoteThreadEx);
215+
const void *found =
216+
Sig::find(exe, size, "B8 38 00 00 00 E8 66 5B 13 00 48 2B E0 45 85 C0 79 2A BA DF 00 00 00");
217+
218+
if (found != nullptr) {
219+
MH_CreateHook((LPVOID)found, (LPVOID)read, nullptr);
220+
MH_EnableHook((LPVOID)found);
221+
}
164222
}
223+
224+
std::thread([]() {
225+
while (doneMagic == false) {
226+
Sleep(1);
227+
}
228+
229+
MH_DisableHook(MH_ALL_HOOKS);
230+
MH_RemoveHook(MH_ALL_HOOKS);
231+
232+
{
233+
const auto remoteThreadEx = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "CreateRemoteThreadEx");
234+
MH_CreateHook((LPVOID)remoteThreadEx, (LPVOID)createThread, (LPVOID *)&oCreateRemoteThreadEx);
235+
MH_EnableHook((LPVOID)remoteThreadEx);
236+
}
237+
}).detach();
238+
}
239+
240+
bool restored = false;
241+
typedef BOOL(WINAPI *WriteProcessMemory_t)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T *);
242+
WriteProcessMemory_t oWriteProcessMemory = nullptr;
243+
BOOL WINAPI writeMem(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize,
244+
SIZE_T *lpNumberOfBytesWritten) {
245+
auto result = oWriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
246+
247+
const auto ntdll = GetModuleHandle(L"ntdll.dll");
248+
uint8_t callcode = ((uint8_t *)GetProcAddress(ntdll, "NtQuerySection"))[4] - 1;
249+
uint8_t restore[] = {0x4C, 0x8B, 0xD1, 0xB8, callcode};
250+
251+
volatile auto ntProtectVirtualMemory = (uint8_t *)GetProcAddress(ntdll, "NtProtectVirtualMemory");
252+
253+
if (restored == false && ntProtectVirtualMemory == lpBaseAddress) {
254+
DWORD oldProtect;
255+
VirtualProtect((LPVOID)ntProtectVirtualMemory, sizeof(restore), PAGE_EXECUTE_READWRITE, &oldProtect);
256+
memcpy(ntProtectVirtualMemory, restore, sizeof(restore));
257+
VirtualProtect((LPVOID)ntProtectVirtualMemory, sizeof(restore), oldProtect, nullptr);
258+
259+
restored = true;
260+
261+
cont();
262+
}
263+
264+
return result;
265+
}
266+
267+
void start() {
268+
MH_Initialize();
269+
270+
MH_CreateHook((LPVOID)WriteProcessMemory, (LPVOID)writeMem, (LPVOID *)&oWriteProcessMemory);
271+
MH_EnableHook((LPVOID)WriteProcessMemory);
165272
}
166273

167274
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {

lol/injector.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ int main() {
7474
CloseHandle(shExecInfo.hProcess);
7575
}
7676

77-
std::cout << "Press any key to exit" << std::endl;
78-
getchar();
77+
std::cout << "Exiting in 5 seconds..." << std::endl;
78+
Sleep(5000);
7979

8080
return 0;
8181
}

0 commit comments

Comments
 (0)