CppUtils/Utils/Utils.cpp

543 lines
14 KiB
C++
Raw Permalink Normal View History

2025-06-05 10:06:43 +08:00
#include "Utils.h"
#include <locale>
#include <Psapi.h>
#include <sstream>
#include <fstream>
#include <codecvt>
#include <iostream>
#include <stdexcept>
#include <TlHelp32.h>
#include <dbghelp.h>
#include <Wtsapi32.h>
#pragma comment(lib, "Dbghelp.lib")
#pragma comment(lib,"Wtsapi32.lib")
#pragma warning(disable: 4267)
#pragma warning(disable: 4244)
#pragma warning(disable: 4018)
DWORD NtBuildVersion()
{
static DWORD res = 0;
if (!res) {
typedef LONG(NTAPI* fnRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
fnRtlGetVersion pRtlGetVersion = NULL;
while (pRtlGetVersion == 0)
{
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
if (ntdll) {
pRtlGetVersion = (fnRtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion");
}
}
RTL_OSVERSIONINFOW osversion{};
pRtlGetVersion(&osversion);
res = osversion.dwBuildNumber;
}
return res;
}
std::vector<PATTERNVALUE> ParserPattern(std::string text)
{
#define IS_HEX(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
#define HEX_TO_VALUE(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' : ((c) >= 'a' && (c) <= 'f') ? (c) - 'a' + 10 : ((c) >= 'A' && (c) <= 'F') ? (c) - 'A' + 10 : 0)
std::vector<PATTERNVALUE> result;
bool firstChar = TRUE;
PATTERNVALUE val = { 0 };
for (char c : text) {
if (IS_HEX(c)) {
if (firstChar) {
val.left = HEX_TO_VALUE(c);
firstChar = FALSE;
}
else {
val.right = HEX_TO_VALUE(c);
result.push_back(val);
val = { 0 };
firstChar = TRUE;
}
}
else if (c == '?' || c == '*') {
if (firstChar) {
val.left = 0;
val.ignore_left = 1;
firstChar = FALSE;
}
else {
val.right = 0;
val.ignore_right = 1;
result.push_back(val);
val = { 0 };
firstChar = TRUE;
}
}
else if (!firstChar && val.ignore_left) {
val.right = 0;
val.ignore_right = 1;
result.push_back(val);
val = { 0 };
firstChar = TRUE;
}
else {
firstChar = TRUE;
}
}
if (!firstChar && (val.left != 0 || val.ignore_left != 0)) {
val.right = 0;
val.ignore_right = 1;
result.push_back(val);
}
#undef IS_HEX
#undef HEX_TO_VALUE
return result;
}
void* FindU64(const char* szModule, ULONG64 value)
{
MODULEINFO mi{ };
if (GetModuleInformation(GetCurrentProcess(), GetModuleHandleA(szModule), &mi, sizeof(mi)))
{
unsigned char* begin = (unsigned char*)mi.lpBaseOfDll;
DWORD size = mi.SizeOfImage;
for (unsigned char* p = begin; p <= (begin + size) - 8; p++)
{
if (*(ULONG64*)p == value)
{
return p;
}
}
}
return NULL;
}
void* FindPattern(const char* szModule, std::string sPattern, int offset)
{
std::vector<PATTERNVALUE> pattern = ParserPattern(sPattern);
if (pattern.size() == 0) return NULL;
MODULEINFO mi{ };
if (GetModuleInformation(GetCurrentProcess(), GetModuleHandleA(szModule), &mi, sizeof(mi)))
{
unsigned char* begin = (unsigned char*)mi.lpBaseOfDll;
DWORD size = mi.SizeOfImage;
for (unsigned char* curr = begin + offset; curr <= (begin + size) - pattern.size(); curr++)
{
for (int i = 0; i < pattern.size(); i++)
{
if (pattern[i].ignore == 0x11) continue;
if (!pattern[i].ignore_left && ((curr[i] & 0xF0) >> 4) != pattern[i].left)goto nxt;
if (!pattern[i].ignore_right && (curr[i] & 0x0F) != pattern[i].right)goto nxt;
}
return curr;
nxt:;
}
}
return NULL;
}
std::vector<void*> FindAllPattern(const char* szModule, std::string sPattern, int offset)
{
std::vector<void*> result = std::vector<void*>();
std::vector<PATTERNVALUE> pattern = ParserPattern(sPattern);
if (pattern.size() == 0) return result;
MODULEINFO mi{ };
HMODULE m = NULL;
if (szModule)
m = LoadLibraryA(szModule);
else
m = GetModuleHandle(NULL);
if (!m)
{
printf("GetModule Infomation Failed!\n");
return result;
}
if (GetModuleInformation(GetCurrentProcess(), m, &mi, sizeof(mi)))
{
unsigned char* begin = (unsigned char*)mi.lpBaseOfDll;
DWORD size = mi.SizeOfImage;
for (unsigned char* curr = begin + offset; curr <= (begin + size) - pattern.size(); curr++)
{
for (int i = 0; i < pattern.size(); i++)
{
if (pattern[i].ignore == 0x11) continue;
if (!pattern[i].ignore_left && ((curr[i] & 0xF0) >> 4) != pattern[i].left)goto nxt;
if (!pattern[i].ignore_right && (curr[i] & 0x0F) != pattern[i].right)goto nxt;
}
result.push_back(curr);
nxt:;
}
}
else
{
printf("GetModule Infomation Failed!\n");
}
return result;
}
void* FindPattern(void* _begin, std::string sPattern, int search_size, int offset)
{
std::vector<PATTERNVALUE> pattern = ParserPattern(sPattern);
if (pattern.size() == 0) return NULL;
unsigned char* begin = (unsigned char*)_begin;
for (unsigned char* curr = begin + offset; curr <= (begin + search_size) - pattern.size(); curr++)
{
for (int i = 0; i < pattern.size(); i++)
{
if (pattern[i].ignore == 0x11) continue;
if (!pattern[i].ignore_left && ((curr[i] & 0xF0) >> 4) != pattern[i].left)goto nxt;
if (!pattern[i].ignore_right && (curr[i] & 0x0F) != pattern[i].right)goto nxt;
}
return curr;
nxt:;
}
return NULL;
}
std::vector<void*> FindAllPattern(void* _begin, std::string sPattern, int search_size, int offset)
{
std::vector<void*> result = std::vector<void*>();
std::vector<PATTERNVALUE> pattern = ParserPattern(sPattern);
if (pattern.size() == 0) return result;
unsigned char* begin = (unsigned char*)_begin;
for (unsigned char* curr = begin + offset; curr <= (begin + search_size) - pattern.size(); curr++)
{
for (int i = 0; i < pattern.size(); i++)
{
if (pattern[i].ignore == 0x11) continue;
if (!pattern[i].ignore_left && ((curr[i] & 0xF0) >> 4) != pattern[i].left)goto nxt;
if (!pattern[i].ignore_right && (curr[i] & 0x0F) != pattern[i].right)goto nxt;
}
result.push_back(curr);
nxt:;
}
return result;
}
void PrintHex(void* ptr, int count, int splitLine)
{
const char keys[] = "0123456789ABCDEF";
uint8_t* tmp = (uint8_t*)ptr;
for (uint8_t* b = tmp; b < tmp + count; b += splitLine)
{
for (int j = 0; j < splitLine && b + j < tmp + count; j++)
{
printf("%c%c ", keys[b[j] / 0x10], keys[b[j] % 0x10]);
}
printf("\n");
}
}
void PrintHex(void* ptr, int count)
{
const char keys[] = "0123456789ABCDEF";
uint8_t* tmp = (uint8_t*)ptr;
for (uint8_t* b = tmp; b < tmp + count; b++)
{
printf("%c%c ", keys[*b / 0x10], keys[*b % 0x10]);
}
}
void MakePermute(std::vector<int> nums, std::vector<std::vector<int>>& result, int start) {
if (start == nums.size() - 1) {
result.push_back(nums);
return;
}
for (int i = start; i < nums.size(); i++) {
std::swap(nums[start], nums[i]);
MakePermute(nums, result, start + 1);
std::swap(nums[start], nums[i]);
}
}
std::wstring GetErrorMessage(DWORD err)
{
LPWSTR errorMsgBuffer = NULL;
DWORD size = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
err,
0,
(LPWSTR)&errorMsgBuffer,
0,
nullptr
);
if (size > 0)
{
std::wstring emsg = std::wstring(errorMsgBuffer);
LocalFree(errorMsgBuffer);
return emsg;
}
return L"Unknown error";
}
PIMAGE_NT_HEADERS RtlImageNtHeader(PVOID Base)
{
static PIMAGE_NT_HEADERS(*_RtlImageNtHeader)(PVOID Base) = NULL;
if (_RtlImageNtHeader == NULL)
{
HMODULE NtBase = GetModuleHandleA("ntdll.dll");
_RtlImageNtHeader = (decltype(_RtlImageNtHeader))GetProcAddress(NtBase, "RtlImageNtHeader");
}
return _RtlImageNtHeader(Base);
}
SIZE_T GetSectionSize(_In_ PVOID DllBase)
{
PIMAGE_NT_HEADERS pNTHeader = RtlImageNtHeader(DllBase);
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD64)pNTHeader + sizeof(IMAGE_NT_HEADERS64));
ULONG nAlign = pNTHeader->OptionalHeader.SectionAlignment;
SIZE_T ImageSize = (pNTHeader->OptionalHeader.SizeOfHeaders + nAlign - 1) / nAlign * nAlign;
for (int i = 0; i < pNTHeader->FileHeader.NumberOfSections; ++i)
{
int CodeSize = pSectionHeader[i].Misc.VirtualSize;
int LoadSize = pSectionHeader[i].SizeOfRawData;
int MaxSize = (LoadSize > CodeSize) ? (LoadSize) : (CodeSize);
int SectionSize = (pSectionHeader[i].VirtualAddress + MaxSize + nAlign - 1) / nAlign * nAlign;
if (ImageSize < SectionSize)
ImageSize = SectionSize;
}
return ImageSize;
}
void EnableDump()
{
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
SetUnhandledExceptionFilter([](EXCEPTION_POINTERS* exceptionInfo) -> LONG {
char processPath[MAX_PATH];
GetModuleFileNameA(NULL, processPath, MAX_PATH);
HANDLE hDumpFile = CreateFileA("crash_dump.dmp", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDumpFile != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ExceptionPointers = exceptionInfo;
dumpInfo.ClientPointers = TRUE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
CloseHandle(hDumpFile);
}
return EXCEPTION_CONTINUE_SEARCH;
});
}
List<void*> CaptureStackTraceEx() {
List<void*> result = List<void*>();
const int MAX_STACKTRACE = 64;
void* stack[MAX_STACKTRACE] = {};
WORD numFrames = RtlCaptureStackBackTrace(0, MAX_STACKTRACE, stack, NULL);
for (int i = 0; i < MAX_STACKTRACE; ++i) {
DWORD64 address = reinterpret_cast<DWORD64>(stack[i]);
result.Add((void*)address);
}
return result;
}
#ifdef ZLIB_VERSION
std::vector<uint8_t> Compress(uint8_t* buffer, int len)
{
std::vector<uint8_t> result = std::vector<uint8_t>();
uLong destLen = compressBound(len);
unsigned char* ostream = (unsigned char*)malloc(destLen);
int res = compress(ostream, &destLen, (const unsigned char*)buffer, len);
if (res == Z_BUF_ERROR) {
return result;
}
if (res == Z_MEM_ERROR) {
return result;
}
int ldx = result.size();
result.resize(destLen);
memcpy(&result.operator[](ldx), ostream, destLen);
return result;
}
std::vector<uint8_t> Decompress(uint8_t* buffer, int len, int maxlen)
{
uLong destLen = maxlen;
std::vector<uint8_t> result = std::vector<uint8_t>();
uint8_t* o2stream = new uint8_t[maxlen];
int des = uncompress(o2stream, &destLen, buffer, len);
result.resize(destLen);
memcpy(result.data(), o2stream, destLen);
return result;
}
std::vector<uint8_t> GDecompress(std::vector<uint8_t> compressedBytes) {
std::vector<uint8_t> uncompressedBytes = std::vector<uint8_t>();
if (compressedBytes.size() == 0)return uncompressedBytes;
unsigned full_length = compressedBytes.size();
unsigned half_length = compressedBytes.size() / 2;
unsigned uncompLength = full_length;
char* uncomp = (char*)calloc(sizeof(char), uncompLength);
z_stream strm;
strm.next_in = (Bytef*)compressedBytes.data();
strm.avail_in = compressedBytes.size();
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
bool done = false;
if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
free(uncomp);
return uncompressedBytes;
}
while (!done) {
if (strm.total_out >= uncompLength) {
char* uncomp2 = (char*)calloc(sizeof(char), uncompLength + half_length);
memcpy(uncomp2, uncomp, uncompLength);
uncompLength += half_length;
free(uncomp);
uncomp = uncomp2;
}
strm.next_out = (Bytef*)(uncomp + strm.total_out);
strm.avail_out = uncompLength - strm.total_out;
int err = inflate(&strm, Z_SYNC_FLUSH);
if (err == Z_STREAM_END) done = true;
else if (err != Z_OK) {
break;
}
}
if (inflateEnd(&strm) != Z_OK) {
free(uncomp);
return uncompressedBytes;
}
for (size_t i = 0; i < strm.total_out; ++i) {
uncompressedBytes.push_back(uncomp[i]);
}
free(uncomp);
return uncompressedBytes;
}
std::vector<uint8_t> GCompress(std::vector<uint8_t> input)
{
std::vector<uint8_t> res = std::vector<uint8_t>();
res.resize(input.size());
z_stream zs;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.avail_in = (uInt)input.size();
zs.next_in = (Bytef*)input.data();
zs.avail_out = (uInt)input.size();
zs.next_out = (Bytef*)res.data();
deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
deflate(&zs, Z_FINISH);
deflateEnd(&zs);
res.resize(zs.total_out);
return res;
}
std::vector<uint8_t> GDecompress(uint8_t* compressedBytes, ULONG len) {
std::vector<uint8_t> uncompressedBytes = std::vector<uint8_t>();
if (len == 0)return uncompressedBytes;
unsigned full_length = len;
unsigned half_length = len / 2;
unsigned uncompLength = full_length;
char* uncomp = (char*)calloc(sizeof(char), uncompLength);
z_stream strm;
strm.next_in = compressedBytes;
strm.avail_in = len;
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
bool done = false;
if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
free(uncomp);
return uncompressedBytes;
}
while (!done) {
if (strm.total_out >= uncompLength) {
char* uncomp2 = (char*)calloc(sizeof(char), uncompLength + half_length);
memcpy(uncomp2, uncomp, uncompLength);
uncompLength += half_length;
free(uncomp);
uncomp = uncomp2;
}
strm.next_out = (Bytef*)(uncomp + strm.total_out);
strm.avail_out = uncompLength - strm.total_out;
int err = inflate(&strm, Z_SYNC_FLUSH);
if (err == Z_STREAM_END) done = true;
else if (err != Z_OK) {
break;
}
}
if (inflateEnd(&strm) != Z_OK) {
free(uncomp);
return uncompressedBytes;
}
for (size_t i = 0; i < strm.total_out; ++i) {
uncompressedBytes.push_back(uncomp[i]);
}
free(uncomp);
return uncompressedBytes;
}
std::vector<uint8_t> GCompress(uint8_t* input, ULONG len)
{
std::vector<uint8_t> res = std::vector<uint8_t>();
res.resize(len);
z_stream zs;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.avail_in = (uInt)len;
zs.next_in = (Bytef*)input;
zs.avail_out = (uInt)len;
zs.next_out = (Bytef*)res.data();
deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
deflate(&zs, Z_FINISH);
deflateEnd(&zs);
res.resize(zs.total_out);
return res;
}
std::vector<uint8_t> GCompress(std::initializer_list<uint8_t> input)
{
return GCompress((uint8_t*)input.begin(), input.size());
}
std::vector<uint8_t> GCompress(std::initializer_list<uint8_t>* input)
{
return GCompress((uint8_t*)input->begin(), input->size());
}
std::string MakeDialogFilterStrring(std::string description, std::vector<std::string> filter)
{
std::string result = description;
result.append("(");
for (auto& str : filter)
{
result.append(str);
result.append(";");
}
result.append(")");
result.append(1, '\0');
for (auto& str : filter)
{
result.append(str);
result.append(";");
}
result.append(2, '\0');
return result;
}
std::string MakeDialogFilterStrring(std::string description, std::string filter)
{
std::string result = description;
result.append("(");
result.append(filter);
result.append(")");
result.append(1, '\0');
result.append(filter);
result.append(2, '\0');
return result;
}
#endif