/*----------------------------------------------------------------------------- * _utility *-----------------------------------------------------------------------------*/ #include "core/stdafx.h" #include "core/logdef.h" #include "public/include/utility.h" /////////////////////////////////////////////////////////////////////////////// // For checking if a specific file exists. BOOL FileExists(const char* szPath) { return fs::exists(szPath); } /////////////////////////////////////////////////////////////////////////////// // For checking if pointer is valid or bad. BOOL IsBadReadPtrV2(void* ptr) { MEMORY_BASIC_INFORMATION mbi = { 0 }; if (::VirtualQuery(ptr, &mbi, sizeof(mbi))) { DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY); bool b = !(mbi.Protect & mask); // check the page is not a guard page if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true; return b; } return true; } /////////////////////////////////////////////////////////////////////////////// // For getting information about the executing module. MODULEINFO GetModuleInfo(const char* szModule) { MODULEINFO modinfo = { 0 }; wchar_t szWtext[256]{}; mbstowcs(szWtext, szModule, strlen(szModule) + 1); HMODULE hModule = GetModuleHandle(szWtext); if (hModule == INVALID_HANDLE_VALUE) { return modinfo; } if (hModule) { GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(MODULEINFO)); } return modinfo; } /////////////////////////////////////////////////////////////////////////////// // For finding a byte pattern in memory of the process. BOOL Compare(const unsigned char* pData, const unsigned char* szPattern, const char* szMask) { for (; *szMask; ++szMask, ++pData, ++szPattern) { if (*szMask == 'x' && *pData != *szPattern) { return false; } } return (*szMask) == NULL; } /////////////////////////////////////////////////////////////////////////////// // For finding a pattern in memory of the process with SIMD. DWORD64 FindPatternSIMD(const char* szModule, const unsigned char* szPattern, const char* szMask) { MODULEINFO mInfo = GetModuleInfo(szModule); DWORD64 dwBase = (DWORD64)mInfo.lpBaseOfDll; DWORD64 dwSize = (DWORD64)mInfo.SizeOfImage; unsigned char* pData = (unsigned char*)dwBase; unsigned int length = (unsigned int)dwSize; const unsigned char* end = pData + length - strlen(szMask); int num_masks = (int)ceil((float)strlen(szMask) / (float)16); int masks[64]; // 64*16 = enough masks for 1024 bytes. memset(masks, 0, num_masks * sizeof(int)); for (int i = 0; i < num_masks; ++i) { for (int j = strnlen(szMask + i * 16, 16) - 1; j >= 0; --j) { if (szMask[i * 16 + j] == 'x') { masks[i] |= 1 << j; } } } __m128i xmm1 = _mm_loadu_si128((const __m128i*) szPattern); __m128i xmm2, xmm3, msks; for (; pData != end; _mm_prefetch((const char*)(++pData + 64), _MM_HINT_NTA)) { if (szPattern[0] == pData[0]) { xmm2 = _mm_loadu_si128((const __m128i*) pData); msks = _mm_cmpeq_epi8(xmm1, xmm2); if ((_mm_movemask_epi8(msks) & masks[0]) == masks[0]) { for (DWORD64 i = 1; i < num_masks; ++i) { xmm2 = _mm_loadu_si128((const __m128i*) (pData + i * 16)); xmm3 = _mm_loadu_si128((const __m128i*) (szPattern + i * 16)); msks = _mm_cmpeq_epi8(xmm2, xmm3); if ((_mm_movemask_epi8(msks) & masks[i]) == masks[i]) { if ((i + 1) == num_masks) { return (DWORD64)pData; } } else goto cont; } return (DWORD64)pData; } }cont:; } return NULL; } /////////////////////////////////////////////////////////////////////////////// // For printing output to the debugger. void DbgPrint(LPCSTR sFormat, ...) { CHAR sBuffer[512] = { 0 }; va_list sArgs = {}; // Get the variable arg pointer. va_start(sArgs, sFormat); // Format print the string. int length = vsnprintf(sBuffer, sizeof(sBuffer), sFormat, sArgs); va_end(sArgs); wchar_t szWtext[512]{}; // Convert to LPCWSTR. mbstowcs(szWtext, sBuffer, strlen(sBuffer) + 1); // Output the string to the debugger. OutputDebugString(szWtext); } /////////////////////////////////////////////////////////////////////////////// // For printing the last error to the console if any. void PrintLastError(void) { DWORD errorMessageID = ::GetLastError(); if (errorMessageID != NULL) { LPSTR messageBuffer = nullptr; size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); spdlog::error("{}\n", messageBuffer); LocalFree(messageBuffer); } } /////////////////////////////////////////////////////////////////////////////// // For dumping data from a buffer to a file on the disk void HexDump(const char* szHeader, int nFunc, const void* pData, int nSize) { static unsigned char szAscii[17] = {}; static std::atomic i = {}, j = {}, k = {}; static std::shared_ptr logger = spdlog::get("default_logger"); // Loop until the function returned to the first caller. while (k == 1) { /*Sleep(75);*/ } k = 1; szAscii[16] = '\0'; // Add new loggers here to replace the placeholder. if (nFunc == 0) { logger = spdlog::get("netchan_packet_logger"); } // Add timestamp. logger->set_level(spdlog::level::trace); logger->set_pattern("%v [%H:%M:%S.%f]\n"); logger->trace("---------------------------------------------------------"); // Disable EOL and create block header. logger->set_pattern("%v"); logger->trace("{:s} ---- LEN BYTES: {}\n:\n", szHeader, nSize); logger->trace("-------- 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\n"); // Output the buffer to the file. for (i = 0; i < nSize; i++) { if (i % nSize == 0) { logger->trace(" 0x{:04X} ", i); } logger->trace("{:02x} ", ((unsigned char*)pData)[i]); if ((reinterpret_cast(pData))[i] >= ' ' && (reinterpret_cast(pData))[i] <= '~') { szAscii[i % 16] = (reinterpret_cast(pData))[i]; } else { szAscii[i % 16] = '.'; } if ((i + 1) % 8 == 0 || i + 1 == nSize) { logger->trace(" "); if ((i + 1) % 16 == 0) { if (i + 1 == nSize) { logger->trace("{:s}\n", szAscii); logger->trace("---------------------------------------------------------------------------\n"); logger->trace("\n"); } else { i++; logger->trace("{:s}\n ", szAscii); logger->trace("0x{:04X} ", i--); } } else if (i + 1 == nSize) { szAscii[(i + 1) % 16] = '\0'; if ((i + 1) % 16 <= 8) { logger->trace(" "); } for (j = (i + 1) % 16; j < 16; j++) { logger->trace(" "); } logger->trace("{:s}\n", szAscii); logger->trace("---------------------------------------------------------------------------\n"); logger->trace("\n"); } } } k = 0; /////////////////////////////////////////////////////////////////////////// } /////////////////////////////////////////////////////////////////////////////// // For creating directories for output streams. string CreateDirectories(string svInput) { fs::path fspPathOut(svInput); string results = fspPathOut.u8string(); StringReplace(svInput, "\\ \\", "\\"); fspPathOut = fspPathOut.parent_path(); fs::create_directories(fspPathOut); return results; } /////////////////////////////////////////////////////////////////////////////// // For converting filepaths to windows filepaths. string ConvertToWinPath(const string& svInput) { char szFilePath[MAX_PATH] = { 0 }; string results; sprintf_s(szFilePath, MAX_PATH, "%s", svInput.c_str()); // Flip forward slashes in filepath to windows-style backslash for (int i = 0; i < strlen(szFilePath); i++) { if (szFilePath[i] == '/') { szFilePath[i] = '\\'; } } return results = szFilePath; } /////////////////////////////////////////////////////////////////////////////// // For encoding data in base64. string Base64Encode(const string& svInput) { string results; int val = 0, valb = -6; for (unsigned char c : svInput) { val = (val << 8) + c; valb += 8; while (valb >= 0) { results.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]); valb -= 6; } } if (valb > -6) { results.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]); } while (results.size() % 4) { results.push_back('='); } return results; } /////////////////////////////////////////////////////////////////////////////// // For decoding data in base64. string Base64Decode(const string& svInput) { string results; int val = 0, valb = -8; vector T(256, -1); for (int i = 0; i < 64; i++) { T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; } for (unsigned char c : svInput) { if (T[c] == -1) { break; } val = (val << 6) + T[c]; valb += 6; if (valb >= 0) { results.push_back(char((val >> valb) & 0xFF)); valb -= 8; } } return results; } /////////////////////////////////////////////////////////////////////////////// // For replacing parts of a given string. bool StringReplace(string& svInput, const string& svFrom, const string& svTo) { size_t start_pos = svInput.find(svFrom); if (start_pos == string::npos) { return false; } svInput.replace(start_pos, svFrom.length(), svTo); return true; } /////////////////////////////////////////////////////////////////////////////// // For escaping special characters in a string. string StringEscape(const string& svInput) { string results; results.reserve(svInput.size()); for (const char c : svInput) { switch (c) { //case '\'': results += "\\'"; break; case '\a': results += "\\a"; break; case '\b': results += "\\b"; break; case '\f': results += "\\f"; break; case '\n': results += "\\n"; break; case '\r': results += "\\r"; break; case '\t': results += "\\t"; break; case '\v': results += "\\v"; break; default: results += c; break; } } return results; } /////////////////////////////////////////////////////////////////////////////// // For unescaping special characters in a string. string StringUnescape(const string& svInput) { string results; results.reserve(svInput.size()); for (const char c : svInput) { switch (c) { //case '\\': results += "\'"; break; case '\\a': results += "\a"; break; case '\\b': results += "\b"; break; case '\\f': results += "\f"; break; case '\\n': results += "\n"; break; case '\\r': results += "\r"; break; case '\\t': results += "\t"; break; case '\\v': results += "\v"; break; default: results += c; break; } } return results; } /////////////////////////////////////////////////////////////////////////////// // For converting a string to an array of bytes. vector StringToBytes(const string& svInput, bool bNullTerminator) { char* pszStringStart = const_cast(svInput.c_str()); char* pszStringEnd = pszStringStart + strlen(svInput.c_str()); vector vBytes = vector{ }; for (char* pszCurrentByte = pszStringStart; pszCurrentByte < pszStringEnd; ++pszCurrentByte) { // Dereference character and push back the byte. vBytes.push_back(*pszCurrentByte); } if (bNullTerminator) { vBytes.push_back(0x0); } return vBytes; }; /////////////////////////////////////////////////////////////////////////////// // For converting a string pattern with wildcards to an array of bytes. vector PatternToBytes(const string& svInput) { char* pszPatternStart = const_cast(svInput.c_str()); char* pszPatternEnd = pszPatternStart + strlen(svInput.c_str()); vector vBytes = vector{ }; for (char* pszCurrentByte = pszPatternStart; pszCurrentByte < pszPatternEnd; ++pszCurrentByte) { if (*pszCurrentByte == '?') { ++pszCurrentByte; if (*pszCurrentByte == '?') { ++pszCurrentByte; // Skip double wildcard. } vBytes.push_back(-1); // Push the byte back as invalid. } else { vBytes.push_back(strtoul(pszCurrentByte, &pszCurrentByte, 16)); } } return vBytes; };