Skip to content

Commit f43289a

Browse files
author
Requiem
committed
feat: SHA256 hash calculation for CLI builds
1 parent 08cfdb1 commit f43289a

1 file changed

Lines changed: 255 additions & 76 deletions

File tree

src/cli.cpp

Lines changed: 255 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,26 @@
2222
* - License: MIT
2323
*/
2424

25-
#include <string>
26-
#include <iostream>
2725
#include <vector>
28-
#include <cstdint>
2926
#include <chrono>
3027

3128
#if (defined(__GNUC__) || defined(__linux__))
32-
#include <unistd.h>
3329
#define CLI_LINUX 1
3430
#else
3531
#define CLI_LINUX 0
3632
#endif
3733

34+
#if (defined(__APPLE__) || defined(__APPLE_CPP__) || defined(__MACH__) || defined(__DARWIN))
35+
#define CLI_APPLE 1
36+
#include <mach-o/dyld.h>
37+
#else
38+
#define CLI_APPLE 0
39+
#endif
3840

3941
#if (defined(_MSC_VER) || defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__))
4042
#define CLI_WINDOWS 1
4143
#define WIN32_LEAN_AND_MEAN
4244
#define NOMINMAX
43-
#include <windows.h>
4445
#else
4546
#define CLI_WINDOWS 0
4647
#endif
@@ -63,6 +64,7 @@ std::string grey = "\x1B[38;2;108;108;108m";
6364
using u8 = std::uint8_t;
6465
using u16 = std::uint16_t;
6566
using u32 = std::uint32_t;
67+
using u64 = std::uint64_t;
6668
using i32 = std::int32_t;
6769

6870
enum arg_enum : u8 {
@@ -141,6 +143,179 @@ class win_ansi_enabler_t
141143
};
142144
#endif
143145

146+
struct SHA256 {
147+
u8 buf[64] = {}; // message block buffer
148+
u32 len = 0; // bytes currently in buf
149+
u64 bits = 0; // total bits processed
150+
u32 s[8] = {}; // from h0 to h7
151+
152+
// Initialize state to SHA-256 IVs so that compiler doesn't complain
153+
void init() {
154+
len = 0;
155+
bits = 0;
156+
s[0] = 0x6a09e667;
157+
s[1] = 0xbb67ae85;
158+
s[2] = 0x3c6ef372;
159+
s[3] = 0xa54ff53a;
160+
s[4] = 0x510e527f;
161+
s[5] = 0x9b05688c;
162+
s[6] = 0x1f83d9ab;
163+
s[7] = 0x5be0cd19;
164+
}
165+
166+
// bitwise helpers
167+
static u32 rotr(u32 x, int n) { return (x >> n) | (x << (32 - n)); }
168+
static u32 ch(u32 x, u32 y, u32 z) { return (x & y) ^ (~x & z); }
169+
static u32 maj(u32 x, u32 y, u32 z) { return (x & y) ^ (x & z) ^ (y & z); }
170+
static u32 ep0(u32 x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
171+
static u32 ep1(u32 x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
172+
static u32 sig0(u32 x) { return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3); }
173+
static u32 sig1(u32 x) { return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10); }
174+
175+
// we need to process one 512-bit block from buf
176+
void transform() {
177+
static const u32 k[64] = {
178+
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
179+
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
180+
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
181+
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
182+
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
183+
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
184+
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
185+
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
186+
};
187+
u32 m[64];
188+
for (u32 i = 0, j = 0; i < 16; ++i, j += 4) {
189+
m[i] = (u32)buf[j] << 24 | (u32)buf[j + 1] << 16 | (u32)buf[j + 2] << 8 | (u32)buf[j + 3];
190+
}
191+
for (u32 i = 16; i < 64; ++i) {
192+
m[i] = sig1(m[i - 2]) + m[i - 7] + sig0(m[i - 15]) + m[i - 16];
193+
}
194+
u32 a = s[0];
195+
u32 b = s[1];
196+
u32 c = s[2];
197+
u32 d = s[3];
198+
u32 e = s[4];
199+
u32 f = s[5];
200+
u32 g = s[6];
201+
u32 h = s[7];
202+
for (u32 i = 0; i < 64; ++i) {
203+
u32 t1 = h + ep1(e) + ch(e, f, g) + k[i] + m[i];
204+
u32 t2 = ep0(a) + maj(a, b, c);
205+
h = g;
206+
g = f;
207+
f = e;
208+
e = d + t1;
209+
d = c;
210+
c = b;
211+
b = a;
212+
a = t1 + t2;
213+
}
214+
s[0] += a;
215+
s[1] += b;
216+
s[2] += c;
217+
s[3] += d;
218+
s[4] += e;
219+
s[5] += f;
220+
s[6] += g;
221+
s[7] += h;
222+
}
223+
224+
// arbitrary bytes into the digest
225+
void update(const u8* data, size_t n) {
226+
for (size_t i = 0; i < n; ++i) {
227+
buf[len++] = data[i];
228+
if (len == 64) {
229+
transform();
230+
bits += 512;
231+
len = 0;
232+
}
233+
}
234+
}
235+
236+
// 32-byte digest IN big-endian
237+
void final(u8 out[32]) {
238+
size_t i = len;
239+
if (len < 56) {
240+
buf[i++] = 0x80;
241+
while (i < 56) buf[i++] = 0;
242+
}
243+
else {
244+
buf[i++] = 0x80;
245+
while (i < 64) buf[i++] = 0;
246+
transform();
247+
for (size_t j = 0; j < 56; ++j) buf[j] = 0;
248+
}
249+
bits += (u64)len * 8;
250+
for (int j = 0; j < 8; ++j) {
251+
buf[63 - j] = (u8)((bits >> (8 * j)) & 0xFF);
252+
}
253+
transform();
254+
for (i = 0; i < 4; ++i) {
255+
for (size_t j = 0; j < 8; ++j) {
256+
out[i + j * 4] = (u8)((s[j] >> (24 - i * 8)) & 0xFF);
257+
}
258+
}
259+
}
260+
};
261+
262+
static std::string exe_path() {
263+
#if (CLI_WINDOWS)
264+
std::vector<char> buf(32768);
265+
DWORD r = GetModuleFileNameA(NULL, buf.data(), (DWORD)buf.size());
266+
if (r == 0 || r >= buf.size()) return {};
267+
return std::string(buf.data(), r);
268+
#elif (CLI_APPLE)
269+
uint32_t sz = 0;
270+
_NSGetExecutablePath(nullptr, &sz);
271+
std::vector<char> b(sz);
272+
if (_NSGetExecutablePath(b.data(), &sz) != 0) return {};
273+
std::vector<char> resolved(PATH_MAX);
274+
if (realpath(b.data(), resolved.data())) {
275+
return std::string(resolved.data());
276+
}
277+
return std::string(b.data());
278+
#else
279+
std::vector<char> b(PATH_MAX);
280+
ssize_t l = ::readlink("/proc/self/exe", b.data(), b.size() - 1);
281+
if (l <= 0) return {};
282+
b[(size_t)l] = '\0';
283+
std::vector<char> resolved(PATH_MAX);
284+
if (realpath(b.data(), resolved.data())) {
285+
return std::string(resolved.data());
286+
}
287+
return std::string(b.data());
288+
#endif
289+
}
290+
291+
std::string compute_self_sha256() {
292+
std::string path = exe_path();
293+
if (path.empty()) return {};
294+
std::ifstream ifs(path, std::ios::binary);
295+
if (!ifs) return {};
296+
SHA256 sha;
297+
sha.init();
298+
299+
std::vector<char> chunk(64 * 1024);
300+
while (ifs) {
301+
ifs.read(chunk.data(), static_cast<std::streamsize>(chunk.size()));
302+
std::streamsize r = ifs.gcount();
303+
if (r > 0) {
304+
sha.update(reinterpret_cast<const u8*>(chunk.data()), static_cast<size_t>(r));
305+
}
306+
}
307+
308+
u8 digest[32];
309+
sha.final(digest);
310+
static const char hex[] = "0123456789abcdef";
311+
std::string out;
312+
out.reserve(64);
313+
for (int i = 0; i < 32; ++i) {
314+
out.push_back(hex[(digest[i] >> 4) & 0xF]);
315+
out.push_back(hex[digest[i] & 0xF]);
316+
}
317+
return out;
318+
}
144319

145320
[[noreturn]] static void help(void) {
146321
std::cout <<
@@ -220,76 +395,75 @@ static const char* color(const u8 score) {
220395

221396
[[noreturn]] static void brand_list() {
222397
std::cout <<
223-
R"(VirtualBox
224-
VMware
225-
VMware Express
226-
VMware ESX
227-
VMware GSX
228-
VMware Workstation
229-
VMware Fusion
230-
bhyve
231-
QEMU
232-
KVM
233-
KVM Hyper-V Enlightenment
234-
QEMU+KVM Hyper-V Enlightenment
235-
QEMU+KVM
236-
Virtual PC
237-
Microsoft Hyper-V
238-
Microsoft Virtual PC/Hyper-V
239-
Parallels
240-
Xen HVM
241-
ACRN
242-
QNX hypervisor
243-
Hybrid Analysis
244-
Sandboxie
245-
Docker
246-
Wine
247-
Anubis
248-
JoeBox
249-
ThreatExpert
250-
CWSandbox
251-
Comodo
252-
Bochs
253-
Lockheed Martin LMHS
254-
NVMM
255-
OpenBSD VMM
256-
Intel HAXM
257-
Unisys s-Par
258-
Cuckoo
259-
BlueStacks
260-
Jailhouse
261-
Apple VZ
262-
Intel KGT (Trusty)
263-
Microsoft Azure Hyper-V
264-
Xbox NanoVisor (Hyper-V)
265-
SimpleVisor
266-
Hyper-V artifact (host with Hyper-V enabled)
267-
User-mode Linux
268-
IBM PowerVM
269-
Google Compute Engine (KVM)
270-
OpenStack (KVM)
271-
KubeVirt (KVM)
272-
AWS Nitro System (KVM-based)
273-
Podman
274-
WSL
275-
OpenVZ
276-
ANY.RUN
277-
Barevisor
278-
HyperPlatform
279-
MiniVisor
280-
Intel TDX
281-
LKVM
282-
AMD SEV
283-
AMD SEV-ES
284-
AMD SEV-SNP
285-
Neko Project II
286-
NoirVisor
287-
Qihoo 360 Sandbox
288-
nsjail
289-
DBVM
290-
UTM
291-
)";
292-
398+
R"(VirtualBox
399+
VMware
400+
VMware Express
401+
VMware ESX
402+
VMware GSX
403+
VMware Workstation
404+
VMware Fusion
405+
bhyve
406+
QEMU
407+
KVM
408+
KVM Hyper-V Enlightenment
409+
QEMU+KVM Hyper-V Enlightenment
410+
QEMU+KVM
411+
Virtual PC
412+
Microsoft Hyper-V
413+
Microsoft Virtual PC/Hyper-V
414+
Parallels
415+
Xen HVM
416+
ACRN
417+
QNX hypervisor
418+
Hybrid Analysis
419+
Sandboxie
420+
Docker
421+
Wine
422+
Anubis
423+
JoeBox
424+
ThreatExpert
425+
CWSandbox
426+
Comodo
427+
Bochs
428+
Lockheed Martin LMHS
429+
NVMM
430+
OpenBSD VMM
431+
Intel HAXM
432+
Unisys s-Par
433+
Cuckoo
434+
BlueStacks
435+
Jailhouse
436+
Apple VZ
437+
Intel KGT (Trusty)
438+
Microsoft Azure Hyper-V
439+
Xbox NanoVisor (Hyper-V)
440+
SimpleVisor
441+
Hyper-V artifact (host with Hyper-V enabled)
442+
User-mode Linux
443+
IBM PowerVM
444+
Google Compute Engine (KVM)
445+
OpenStack (KVM)
446+
KubeVirt (KVM)
447+
AWS Nitro System (KVM-based)
448+
Podman
449+
WSL
450+
OpenVZ
451+
ANY.RUN
452+
Barevisor
453+
HyperPlatform
454+
MiniVisor
455+
Intel TDX
456+
LKVM
457+
AMD SEV
458+
AMD SEV-ES
459+
AMD SEV-SNP
460+
Neko Project II
461+
NoirVisor
462+
Qihoo 360 Sandbox
463+
nsjail
464+
DBVM
465+
UTM
466+
)";
293467
std::exit(0);
294468
}
295469

@@ -687,7 +861,7 @@ static void general(
687861
const VM::enum_flags dynamic
688862
) {
689863
bool notes_enabled = false;
690-
864+
691865
if (arg_bitset.test(NO_ANSI)) {
692866
detected = ("[ DETECTED ]");
693867
not_detected = ("[NOT DETECTED]");
@@ -723,6 +897,11 @@ static void general(
723897
}
724898
#endif
725899

900+
const std::string hash = compute_self_sha256();
901+
if (!hash.empty()) {
902+
std::cout << "SHA256: " << hash << '\n';
903+
}
904+
726905
const auto t1 = std::chrono::high_resolution_clock::now();
727906

728907
checker(VM::VMID, "VMID");

0 commit comments

Comments
 (0)