mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2025-04-03 18:00:08 +03:00
When memory is released and reallocated, a random security value called a canary is written to the before/after area of memory, and if the value has been modified, the process is terminated (restarted) for safety, assuming it is a buffer overflow of the memory area. This feature may effectively prevent confidentiality or integrity violations in the event that some heap area overflow vulnerability is discovered in this system in the future.
1095 lines
21 KiB
C
1095 lines
21 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Mayaqua Kernel
|
|
|
|
|
|
// Mayaqua.c
|
|
// Mayaqua Kernel program
|
|
|
|
#include "Mayaqua.h"
|
|
|
|
#include "Encrypt.h"
|
|
#include "FileIO.h"
|
|
#include "GlobalConst.h"
|
|
#include "Internat.h"
|
|
#include "Memory.h"
|
|
#include "Microsoft.h"
|
|
#include "Network.h"
|
|
#include "Object.h"
|
|
#include "OS.h"
|
|
#include "Secure.h"
|
|
#include "Str.h"
|
|
#include "Table.h"
|
|
#include "Tick64.h"
|
|
#include "Tracking.h"
|
|
|
|
#include <locale.h>
|
|
#include <stdlib.h>
|
|
|
|
// Global variable
|
|
bool g_memcheck; // Enable memory check
|
|
bool g_debug; // Debug mode
|
|
UINT64 kernel_status[NUM_KERNEL_STATUS]; // Kernel state
|
|
UINT64 kernel_status_max[NUM_KERNEL_STATUS]; // Kernel state (maximum value)
|
|
LOCK *kernel_status_lock[NUM_KERNEL_STATUS]; // Kernel state lock
|
|
bool kernel_status_inited = false; // Kernel state initialization flag
|
|
bool g_little_endian = true;
|
|
char *cmdline = NULL; // Command line
|
|
wchar_t *uni_cmdline = NULL; // Unicode command line
|
|
bool g_foreground = false; // Execute service in foreground mode
|
|
|
|
// Static variable
|
|
static char *exename = NULL; // EXE file name (ANSI)
|
|
static wchar_t *exename_w = NULL; // EXE file name (Unicode)
|
|
static TOKEN_LIST *cmdline_token = NULL; // Command line token
|
|
static UNI_TOKEN_LIST *cmdline_uni_token = NULL; // Command line token (Unicode)
|
|
static OS_INFO *os_info = NULL; // OS information
|
|
static bool dot_net_mode = false;
|
|
static bool minimal_mode = false;
|
|
static UINT last_time_check = 0;
|
|
static UINT first_time_check = 0;
|
|
static bool is_nt = false;
|
|
static bool is_ham_mode = false;
|
|
static UINT init_mayaqua_counter = 0;
|
|
static bool use_probe = false;
|
|
static BUF *probe_buf = NULL;
|
|
static LOCK *probe_lock = NULL;
|
|
static UINT64 probe_start = 0;
|
|
static UINT64 probe_last = 0;
|
|
static bool probe_enabled = false;
|
|
|
|
// The function which should be called once as soon as possible after the process is started
|
|
static bool init_proc_once_flag = false;
|
|
void InitProcessCallOnce()
|
|
{
|
|
if (init_proc_once_flag == false)
|
|
{
|
|
init_proc_once_flag = true;
|
|
|
|
InitCanaryRand();
|
|
|
|
#ifdef OS_WIN32
|
|
MsInitProcessCallOnce();
|
|
#endif // OS_WIN32
|
|
}
|
|
}
|
|
|
|
// Calculate the checksum
|
|
USHORT CalcChecksum16(void *buf, UINT size)
|
|
{
|
|
int sum = 0;
|
|
USHORT *addr = (USHORT *)buf;
|
|
int len = (int)size;
|
|
USHORT *w = addr;
|
|
int nleft = len;
|
|
USHORT answer = 0;
|
|
|
|
while (nleft > 1)
|
|
{
|
|
USHORT ww = 0;
|
|
Copy(&ww, w++, sizeof(USHORT));
|
|
sum += ww;
|
|
nleft -= 2;
|
|
}
|
|
|
|
if (nleft == 1)
|
|
{
|
|
*(UCHAR *)(&answer) = *(UCHAR *)w;
|
|
sum += answer;
|
|
}
|
|
|
|
sum = (sum >> 16) + (sum & 0xffff);
|
|
sum += (sum >> 16);
|
|
|
|
answer = ~sum;
|
|
|
|
return answer;
|
|
}
|
|
|
|
// Writing a probe with the data
|
|
void WriteProbeData(char *filename, UINT line, char *str, void *data, UINT size)
|
|
{
|
|
char tmp[MAX_SIZE];
|
|
USHORT cs;
|
|
|
|
if (IsProbeEnabled() == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Take a checksum of the data
|
|
if (size != 0)
|
|
{
|
|
cs = CalcChecksum16(data, size);
|
|
}
|
|
else
|
|
{
|
|
cs = 0;
|
|
}
|
|
|
|
// Generating a String
|
|
snprintf(tmp, sizeof(tmp), "\"%s\" (Size=%5u, Crc=0x%04X)", str, size, cs);
|
|
|
|
WriteProbe(filename, line, tmp);
|
|
}
|
|
|
|
// Writing Probe
|
|
void WriteProbe(char *filename, UINT line, char *str)
|
|
{
|
|
#ifdef OS_WIN32
|
|
char *s;
|
|
char tmp[MAX_SIZE];
|
|
char tmp2[MAX_SIZE];
|
|
UINT64 now = 0;
|
|
UINT64 time;
|
|
|
|
if (IsProbeEnabled() == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
now = MsGetHiResCounter();
|
|
|
|
Lock(probe_lock);
|
|
{
|
|
UINT64 diff;
|
|
|
|
time = MsGetHiResTimeSpanUSec(now - probe_start);
|
|
|
|
diff = time - probe_last;
|
|
|
|
if (time < probe_last)
|
|
{
|
|
diff = 0;
|
|
}
|
|
|
|
probe_last = time;
|
|
|
|
ToStr64(tmp, time);
|
|
MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
|
|
WriteBuf(probe_buf, tmp2, StrLen(tmp2));
|
|
WriteBuf(probe_buf, tmp, StrLen(tmp));
|
|
|
|
s = " [+";
|
|
WriteBuf(probe_buf, s, StrLen(s));
|
|
|
|
ToStr64(tmp, diff);
|
|
MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
|
|
WriteBuf(probe_buf, tmp2, StrLen(tmp2));
|
|
WriteBuf(probe_buf, tmp, StrLen(tmp));
|
|
|
|
s = "] - ";
|
|
WriteBuf(probe_buf, s, StrLen(s));
|
|
|
|
WriteBuf(probe_buf, filename, StrLen(filename));
|
|
|
|
s = "(";
|
|
WriteBuf(probe_buf, s, StrLen(s));
|
|
|
|
ToStr64(tmp, (UINT64)line);
|
|
WriteBuf(probe_buf, tmp, StrLen(tmp));
|
|
|
|
s = "): ";
|
|
WriteBuf(probe_buf, s, StrLen(s));
|
|
|
|
WriteBuf(probe_buf, str, StrLen(str));
|
|
|
|
s = "\r\n";
|
|
WriteBuf(probe_buf, s, StrLen(s));
|
|
}
|
|
Unlock(probe_lock);
|
|
#endif // OS_WIN32
|
|
}
|
|
|
|
// Initialization of Probe
|
|
void InitProbe()
|
|
{
|
|
probe_buf = NewBuf();
|
|
probe_lock = NewLock();
|
|
probe_enabled = false;
|
|
|
|
probe_start = 0;
|
|
|
|
#ifdef OS_WIN32
|
|
probe_start = MsGetHiResCounter();
|
|
#endif // OS_WIN32
|
|
}
|
|
|
|
// Release of Probe
|
|
void FreeProbe()
|
|
{
|
|
if (probe_buf->Size >= 1)
|
|
{
|
|
SYSTEMTIME st;
|
|
char filename[MAX_SIZE];
|
|
|
|
// Write all to the file
|
|
MakeDirEx("@probe_log");
|
|
|
|
LocalTime(&st);
|
|
|
|
snprintf(filename, sizeof(filename), "@probe_log/%04u%02u%02u_%02u%02u%02u.log",
|
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
|
|
|
DumpBuf(probe_buf, filename);
|
|
}
|
|
|
|
FreeBuf(probe_buf);
|
|
DeleteLock(probe_lock);
|
|
}
|
|
|
|
// Set enable / disable the Probe
|
|
void EnableProbe(bool enable)
|
|
{
|
|
probe_enabled = enable;
|
|
}
|
|
|
|
// Get whether the Probe is enabled?
|
|
bool IsProbeEnabled()
|
|
{
|
|
#ifndef USE_PROBE
|
|
return false;
|
|
#else // USE_PROBE
|
|
return probe_enabled;
|
|
#endif // USE_PROBE
|
|
}
|
|
|
|
// Set the Ham mode
|
|
void SetHamMode()
|
|
{
|
|
is_ham_mode = true;
|
|
}
|
|
|
|
// Get whether in Ham mode
|
|
bool IsHamMode()
|
|
{
|
|
return is_ham_mode;
|
|
}
|
|
|
|
// Display the time from the previous call to now
|
|
void TimeCheck()
|
|
{
|
|
#ifdef OS_WIN32
|
|
UINT now, ret, total;
|
|
now = Win32GetTick();
|
|
if (last_time_check == 0)
|
|
{
|
|
ret = 0;
|
|
}
|
|
else
|
|
{
|
|
ret = now - last_time_check;
|
|
}
|
|
last_time_check = now;
|
|
|
|
if (first_time_check == 0)
|
|
{
|
|
first_time_check = now;
|
|
}
|
|
|
|
total = now - first_time_check;
|
|
|
|
printf(" -- %3.3f / %3.3f\n", (double)ret / 1000.0f, (double)total / 1000.0f);
|
|
#endif // OS_WIN32
|
|
}
|
|
|
|
// Whether this system is IA64
|
|
bool IsIA64()
|
|
{
|
|
if (Is64() == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifndef MAYAQUA_IA_64
|
|
return false;
|
|
#else // MAYAQUA_IA_64
|
|
return true;
|
|
#endif // MAYAQUA_IA_64
|
|
}
|
|
|
|
// Whether in x64
|
|
bool IsX64()
|
|
{
|
|
if (Is64() == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifndef MAYAQUA_IA_64
|
|
return true;
|
|
#else // MAYAQUA_IA_64
|
|
return false;
|
|
#endif // MAYAQUA_IA_64
|
|
}
|
|
|
|
// Whether 64bit
|
|
bool Is64()
|
|
{
|
|
#ifdef CPU_64
|
|
return true;
|
|
#else // CPU_64
|
|
return false;
|
|
#endif // CPU_64
|
|
}
|
|
|
|
// Whether 32bit
|
|
bool Is32()
|
|
{
|
|
return Is64() ? false : true;
|
|
}
|
|
|
|
// Acquisition whether in .NET mode
|
|
bool MayaquaIsDotNetMode()
|
|
{
|
|
return dot_net_mode;
|
|
}
|
|
|
|
// Check the endian
|
|
void CheckEndian()
|
|
{
|
|
unsigned short test;
|
|
UCHAR *buf;
|
|
|
|
test = 0x1234;
|
|
buf = (UCHAR *)&test;
|
|
if (buf[0] == 0x12)
|
|
{
|
|
g_little_endian = false;
|
|
}
|
|
else
|
|
{
|
|
g_little_endian = true;
|
|
}
|
|
}
|
|
|
|
// Minimize mode
|
|
void MayaquaMinimalMode()
|
|
{
|
|
minimal_mode = true;
|
|
}
|
|
bool MayaquaIsMinimalMode()
|
|
{
|
|
return minimal_mode;
|
|
}
|
|
|
|
// Whether in NT
|
|
bool IsNt()
|
|
{
|
|
return is_nt;
|
|
}
|
|
|
|
// Initialization of Mayaqua library
|
|
void InitMayaqua(bool memcheck, bool debug, int argc, char **argv)
|
|
{
|
|
wchar_t tmp[MAX_PATH];
|
|
UCHAR hash[SHA1_SIZE];
|
|
|
|
if ((init_mayaqua_counter++) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
InitProcessCallOnce();
|
|
|
|
g_memcheck = memcheck;
|
|
g_debug = debug;
|
|
cmdline = NULL;
|
|
if (dot_net_mode == false)
|
|
{
|
|
// Fail this for some reason when this is called this in .NET mode
|
|
setbuf(stdout, NULL);
|
|
}
|
|
|
|
#ifdef OS_UNIX
|
|
g_foreground = (argc >= 3 && StrCmpi(argv[2], UNIX_SVC_ARG_FOREGROUND) == 0);
|
|
#else
|
|
g_foreground = false;
|
|
#endif // OS_UNIX
|
|
|
|
// Acquisition whether NT
|
|
#ifdef OS_WIN32
|
|
is_nt = Win32IsNt();
|
|
#endif // OS_WIN32
|
|
|
|
// Check endian
|
|
CheckEndian();
|
|
|
|
#ifdef OS_WIN32
|
|
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
|
#endif // OS_WIN32
|
|
|
|
// Set the locale information of the CRT to the Japanese
|
|
setlocale(LC_ALL, "");
|
|
|
|
// Initialization of OS
|
|
OSInit();
|
|
|
|
// Initialize the random number
|
|
srand((UINT)SystemTime64());
|
|
|
|
tick_manual_lock = NewLock();
|
|
|
|
// Initialization of CRC32
|
|
InitCrc32();
|
|
|
|
// Initialization of the FIFO system
|
|
InitFifo();
|
|
|
|
// Initialize the Kernel status
|
|
InitKernelStatus();
|
|
|
|
if (IsTrackingEnabled())
|
|
{
|
|
// Initialize the tracking
|
|
InitTracking();
|
|
}
|
|
|
|
// Initialization of thread pool
|
|
InitThreading();
|
|
|
|
// Initialize the string library
|
|
InitStringLibrary();
|
|
|
|
// Initialization of the locale information
|
|
SetLocale(NULL);
|
|
|
|
// Initialization of the crypt library
|
|
InitCryptLibrary();
|
|
|
|
// Initialization of the real-time clock
|
|
InitTick64();
|
|
|
|
// Initialize the network communication module
|
|
InitNetwork();
|
|
|
|
// Initialization of the acquisition of the EXE file name
|
|
InitGetExeName(argc >= 1 ? argv[0] : NULL);
|
|
|
|
// Initialization of the command line string
|
|
InitCommandLineStr(argc, argv);
|
|
|
|
// Initialization of OS information
|
|
InitOsInfo();
|
|
|
|
// Initialization of the operating system-specific module
|
|
#ifdef OS_WIN32
|
|
MsInit(); // Microsoft Win32
|
|
#endif // OS_WIN32
|
|
|
|
// Initialization of the security token module
|
|
InitSecure();
|
|
|
|
if (OSIsSupportedOs() == false)
|
|
{
|
|
// Abort
|
|
exit(0);
|
|
}
|
|
|
|
// RSA Check
|
|
if (RsaCheckEx() == false)
|
|
{
|
|
// Abort
|
|
Alert("OpenSSL Library Init Failed. (too old?)\nPlease install the latest version of OpenSSL.\n\n", "RsaCheck()");
|
|
exit(0);
|
|
}
|
|
|
|
// Initialization of HamCore file system
|
|
InitHamcore();
|
|
|
|
// Initialization of string table routine
|
|
InitTable();
|
|
|
|
if (exename == NULL)
|
|
{
|
|
// Executable file name
|
|
exename = CopyStr("unknown");
|
|
}
|
|
|
|
// Check whether the executable file name of themselves is found
|
|
// (If not found, quit because this is started in strange path)
|
|
GetExeNameW(tmp, sizeof(tmp));
|
|
if (IsFileExistsW(tmp) == false)
|
|
{
|
|
wchar_t tmp2[MAX_SIZE];
|
|
|
|
UniFormat(tmp2, sizeof(tmp2),
|
|
L"Error: Executable binary file \"%s\" not found.\r\n\r\n"
|
|
L"Please execute program with full path.\r\n",
|
|
tmp);
|
|
|
|
AlertW(tmp2, NULL);
|
|
_exit(0);
|
|
}
|
|
|
|
CheckUnixTempDir();
|
|
|
|
// Initialization of Probe
|
|
InitProbe();
|
|
|
|
// Initialization of Machine Hash
|
|
GetCurrentMachineIpProcessHash(hash);
|
|
|
|
// Reading Private IP file
|
|
LoadPrivateIPFile();
|
|
}
|
|
|
|
// Release of Mayaqua library
|
|
void FreeMayaqua()
|
|
{
|
|
if ((--init_mayaqua_counter) > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Release of Private IP File
|
|
FreePrivateIPFile();
|
|
|
|
// Release of Probe
|
|
FreeProbe();
|
|
|
|
// Delete the table
|
|
FreeTable();
|
|
|
|
// Release of security token module
|
|
FreeSecure();
|
|
|
|
// Release of the operating system specific module
|
|
#ifdef OS_WIN32
|
|
MsFree();
|
|
#endif // OS_WIN32
|
|
|
|
// Release of OS information
|
|
FreeOsInfo();
|
|
|
|
// Release of HamCore file system
|
|
FreeHamcore();
|
|
|
|
// Release of the command line string
|
|
FreeCommandLineStr();
|
|
|
|
// Release of the command line token
|
|
FreeCommandLineTokens();
|
|
|
|
// Release of network communication module
|
|
FreeNetwork();
|
|
|
|
// Release of real-time clock
|
|
FreeTick64();
|
|
|
|
// Release of the string library
|
|
FreeStringLibrary();
|
|
|
|
// Release of thread pool
|
|
FreeThreading();
|
|
|
|
// Release of crypt library
|
|
FreeCryptLibrary();
|
|
|
|
if (IsTrackingEnabled())
|
|
{
|
|
// Show the kernel status
|
|
if (g_debug)
|
|
{
|
|
PrintKernelStatus();
|
|
}
|
|
|
|
// Display the debug information
|
|
if (g_memcheck)
|
|
{
|
|
PrintDebugInformation();
|
|
}
|
|
|
|
// Release the tracking
|
|
FreeTracking();
|
|
}
|
|
|
|
// Release of the kernel status
|
|
FreeKernelStatus();
|
|
|
|
DeleteLock(tick_manual_lock);
|
|
tick_manual_lock = NULL;
|
|
|
|
// Release of OS
|
|
OSFree();
|
|
}
|
|
|
|
// Check whether /tmp is available in the UNIX
|
|
void CheckUnixTempDir()
|
|
{
|
|
if (OS_IS_UNIX(GetOsInfo()->OsType))
|
|
{
|
|
char tmp[128], tmp2[64];
|
|
UINT64 now = SystemTime64();
|
|
IO *o;
|
|
|
|
MakeDir("/tmp");
|
|
|
|
Format(tmp2, sizeof(tmp2), "%I64u", now);
|
|
|
|
Format(tmp, sizeof(tmp), "/tmp/.%s", tmp2);
|
|
|
|
o = FileCreate(tmp);
|
|
if (o == NULL)
|
|
{
|
|
o = FileOpen(tmp, false);
|
|
if (o == NULL)
|
|
{
|
|
Print("Unable to use /tmp.\n\n");
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
FileClose(o);
|
|
|
|
FileDelete(tmp);
|
|
}
|
|
}
|
|
|
|
// Show an alert
|
|
void Alert(char *msg, char *caption)
|
|
{
|
|
OSAlert(msg, caption);
|
|
}
|
|
void AlertW(wchar_t *msg, wchar_t *caption)
|
|
{
|
|
OSAlertW(msg, caption);
|
|
}
|
|
|
|
// Get the OS type
|
|
UINT GetOsType()
|
|
{
|
|
OS_INFO *i = GetOsInfo();
|
|
|
|
if (i == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return i->OsType;
|
|
}
|
|
|
|
// Getting OS information
|
|
OS_INFO *GetOsInfo()
|
|
{
|
|
return os_info;
|
|
}
|
|
|
|
// Initialization of OS information
|
|
void InitOsInfo()
|
|
{
|
|
if (os_info != NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
os_info = ZeroMalloc(sizeof(OS_INFO));
|
|
|
|
OSGetOsInfo(os_info);
|
|
}
|
|
|
|
// Release of OS information
|
|
void FreeOsInfo()
|
|
{
|
|
if (os_info == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Free(os_info->OsSystemName);
|
|
Free(os_info->OsProductName);
|
|
Free(os_info->OsVendorName);
|
|
Free(os_info->OsVersion);
|
|
Free(os_info->KernelName);
|
|
Free(os_info->KernelVersion);
|
|
Free(os_info);
|
|
|
|
os_info = NULL;
|
|
}
|
|
|
|
// Get the Unicode command line tokens
|
|
UNI_TOKEN_LIST *GetCommandLineUniToken()
|
|
{
|
|
if (cmdline_uni_token == NULL)
|
|
{
|
|
return UniNullToken();
|
|
}
|
|
else
|
|
{
|
|
return UniCopyToken(cmdline_uni_token);
|
|
}
|
|
}
|
|
|
|
// Getting the command line tokens
|
|
TOKEN_LIST *GetCommandLineToken()
|
|
{
|
|
if (cmdline_token == NULL)
|
|
{
|
|
return NullToken();
|
|
}
|
|
else
|
|
{
|
|
return CopyToken(cmdline_token);
|
|
}
|
|
}
|
|
|
|
// Convert the command line string into tokens
|
|
void ParseCommandLineTokens()
|
|
{
|
|
if (cmdline_token != NULL)
|
|
{
|
|
FreeToken(cmdline_token);
|
|
}
|
|
cmdline_token = ParseCmdLine(cmdline);
|
|
|
|
if (cmdline_uni_token != NULL)
|
|
{
|
|
UniFreeToken(cmdline_uni_token);
|
|
}
|
|
cmdline_uni_token = UniParseCmdLine(uni_cmdline);
|
|
}
|
|
|
|
// Release command line tokens
|
|
void FreeCommandLineTokens()
|
|
{
|
|
if (cmdline_token != NULL)
|
|
{
|
|
FreeToken(cmdline_token);
|
|
}
|
|
cmdline_token = NULL;
|
|
|
|
if (cmdline_uni_token != NULL)
|
|
{
|
|
UniFreeToken(cmdline_uni_token);
|
|
}
|
|
cmdline_uni_token = NULL;
|
|
}
|
|
|
|
// Initialization of the command line string
|
|
void InitCommandLineStr(int argc, char **argv)
|
|
{
|
|
if (argc >= 1)
|
|
{
|
|
#ifdef OS_UNIX
|
|
exename_w = CopyUtfToUni(argv[0]);
|
|
exename = CopyUniToStr(exename_w);
|
|
#else // OS_UNIX
|
|
exename = CopyStr(argv[0]);
|
|
exename_w = CopyStrToUni(exename);
|
|
#endif // OS_UNIX
|
|
}
|
|
if (argc < 2 || argv == NULL)
|
|
{
|
|
// No command-line string
|
|
SetCommandLineStr(NULL);
|
|
}
|
|
else
|
|
{
|
|
// There are command-line string
|
|
int i, total_len = 1;
|
|
char *tmp;
|
|
|
|
for (i = 1;i < argc;i++)
|
|
{
|
|
total_len += StrLen(argv[i]) * 2 + 32;
|
|
}
|
|
tmp = ZeroMalloc(total_len);
|
|
|
|
for (i = 1;i < argc;i++)
|
|
{
|
|
UINT s_size = StrLen(argv[i]) * 2;
|
|
char *s = ZeroMalloc(s_size);
|
|
bool dq = (SearchStrEx(argv[i], " ", 0, true) != INFINITE);
|
|
ReplaceStrEx(s, s_size, argv[i], "\"", "\"\"", true);
|
|
if (dq)
|
|
{
|
|
StrCat(tmp, total_len, "\"");
|
|
}
|
|
StrCat(tmp, total_len, s);
|
|
if (dq)
|
|
{
|
|
StrCat(tmp, total_len, "\"");
|
|
}
|
|
StrCat(tmp, total_len, " ");
|
|
Free(s);
|
|
}
|
|
|
|
Trim(tmp);
|
|
SetCommandLineStr(tmp);
|
|
Free(tmp);
|
|
}
|
|
}
|
|
|
|
// Release of the command line string
|
|
void FreeCommandLineStr()
|
|
{
|
|
SetCommandLineStr(NULL);
|
|
|
|
if (exename != NULL)
|
|
{
|
|
Free(exename);
|
|
exename = NULL;
|
|
}
|
|
|
|
if (exename_w != NULL)
|
|
{
|
|
Free(exename_w);
|
|
exename_w = NULL;
|
|
}
|
|
}
|
|
|
|
// Get the Unicode command line string
|
|
wchar_t *GetCommandLineUniStr()
|
|
{
|
|
if (uni_cmdline == NULL)
|
|
{
|
|
return UniCopyStr(L"");
|
|
}
|
|
else
|
|
{
|
|
return UniCopyStr(uni_cmdline);
|
|
}
|
|
}
|
|
|
|
// Get the command line string
|
|
char *GetCommandLineStr()
|
|
{
|
|
if (cmdline == NULL)
|
|
{
|
|
return CopyStr("");
|
|
}
|
|
else
|
|
{
|
|
return CopyStr(cmdline);
|
|
}
|
|
}
|
|
|
|
// Set the Unicode command line string
|
|
void SetCommandLineUniStr(wchar_t *str)
|
|
{
|
|
if (uni_cmdline != NULL)
|
|
{
|
|
Free(uni_cmdline);
|
|
}
|
|
if (str == NULL)
|
|
{
|
|
uni_cmdline = NULL;
|
|
}
|
|
else
|
|
{
|
|
uni_cmdline = CopyUniStr(str);
|
|
}
|
|
|
|
ParseCommandLineTokens();
|
|
}
|
|
|
|
// Set the command-line string
|
|
void SetCommandLineStr(char *str)
|
|
{
|
|
// Validate arguments
|
|
if (str == NULL)
|
|
{
|
|
if (cmdline != NULL)
|
|
{
|
|
Free(cmdline);
|
|
}
|
|
cmdline = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (cmdline != NULL)
|
|
{
|
|
Free(cmdline);
|
|
}
|
|
cmdline = CopyStr(str);
|
|
}
|
|
|
|
if (cmdline == NULL)
|
|
{
|
|
if (uni_cmdline != NULL)
|
|
{
|
|
Free(uni_cmdline);
|
|
uni_cmdline = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (uni_cmdline != NULL)
|
|
{
|
|
Free(uni_cmdline);
|
|
}
|
|
uni_cmdline = CopyStrToUni(cmdline);
|
|
}
|
|
|
|
ParseCommandLineTokens();
|
|
}
|
|
|
|
// Display the kernel status
|
|
void PrintKernelStatus()
|
|
{
|
|
bool leaked = false;
|
|
|
|
Print("\n");
|
|
Print(
|
|
" --------- Mayaqua Kernel Status ---------\n"
|
|
" Malloc Count ............... %u\n"
|
|
" ReAlloc Count .............. %u\n"
|
|
" Free Count ................. %u\n"
|
|
" Total Memory Size .......... %I64u bytes\n"
|
|
" * Current Memory Blocks ...... %u Blocks (Peek: %u)\n"
|
|
" Total Memory Blocks ........ %u Blocks\n"
|
|
" * Current MemPool Blocks ..... %u Blocks (Peek: %u)\n"
|
|
" Total MemPool Mallocs ...... %u Mallocs\n"
|
|
" Total MemPool ReAllocs ..... %u ReAllocs\n"
|
|
" NewLock Count .............. %u\n"
|
|
" DeleteLock Count ........... %u\n"
|
|
" * Current Lock Objects ....... %u Objects\n"
|
|
" * Current Locked Objects ..... %u Objects\n"
|
|
" NewRef Count ............... %u\n"
|
|
" FreeRef Count .............. %u\n"
|
|
" * Current Ref Objects ........ %u Objects\n"
|
|
" * Current Ref Count .......... %u Refs\n"
|
|
" GetTime Count .............. %u\n"
|
|
" GetTick Count .............. %u\n"
|
|
" NewThread Count ............ %u\n"
|
|
" FreeThread Count ........... %u\n"
|
|
" * Current Threads ............ %u Threads\n"
|
|
" Wait For Event Count ....... %u\n\n",
|
|
KS_GET(KS_MALLOC_COUNT),
|
|
KS_GET(KS_REALLOC_COUNT),
|
|
KS_GET(KS_FREE_COUNT),
|
|
KS_GET64(KS_TOTAL_MEM_SIZE),
|
|
KS_GET(KS_CURRENT_MEM_COUNT),
|
|
KS_GETMAX(KS_CURRENT_MEM_COUNT),
|
|
KS_GET(KS_TOTAL_MEM_COUNT),
|
|
KS_GET(KS_MEMPOOL_CURRENT_NUM),
|
|
KS_GETMAX(KS_MEMPOOL_CURRENT_NUM),
|
|
KS_GET(KS_MEMPOOL_MALLOC_COUNT),
|
|
KS_GET(KS_MEMPOOL_REALLOC_COUNT),
|
|
KS_GET(KS_NEWLOCK_COUNT),
|
|
KS_GET(KS_DELETELOCK_COUNT),
|
|
KS_GET(KS_CURRENT_LOCK_COUNT),
|
|
KS_GET(KS_CURRENT_LOCKED_COUNT),
|
|
KS_GET(KS_NEWREF_COUNT),
|
|
KS_GET(KS_FREEREF_COUNT),
|
|
KS_GET(KS_CURRENT_REF_COUNT),
|
|
KS_GET(KS_CURRENT_REFED_COUNT),
|
|
KS_GET(KS_GETTIME_COUNT),
|
|
KS_GET(KS_GETTICK_COUNT),
|
|
KS_GET(KS_NEWTHREAD_COUNT),
|
|
KS_GET(KS_FREETHREAD_COUNT),
|
|
KS_GET(KS_NEWTHREAD_COUNT) - KS_GET(KS_FREETHREAD_COUNT),
|
|
KS_GET(KS_WAIT_COUNT)
|
|
);
|
|
|
|
if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
|
|
KS_GET(KS_MEMPOOL_CURRENT_NUM) != 0 ||
|
|
KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
|
|
{
|
|
leaked = true;
|
|
}
|
|
|
|
if (leaked)
|
|
{
|
|
Print(" !!! MEMORY LEAKS DETECTED !!!\n\n");
|
|
if (g_memcheck == false)
|
|
{
|
|
if (IsHamMode())
|
|
{
|
|
Print(" Enable /memcheck startup option to see the leaking memory heap.\n");
|
|
Print(" Press Enter key to exit the process.\n");
|
|
}
|
|
GetLine(NULL, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Print(" @@@ NO MEMORY LEAKS @@@\n\n");
|
|
}
|
|
}
|
|
|
|
// Initialize Kernel status
|
|
void InitKernelStatus()
|
|
{
|
|
UINT i;
|
|
|
|
// Memory initialization
|
|
Zero(kernel_status, sizeof(kernel_status));
|
|
Zero(kernel_status_max, sizeof(kernel_status_max));
|
|
|
|
// Lock initialization
|
|
for (i = 0;i < NUM_KERNEL_STATUS;i++)
|
|
{
|
|
kernel_status_lock[i] = OSNewLock();
|
|
}
|
|
|
|
kernel_status_inited = true;
|
|
}
|
|
|
|
// Release of the kernel status
|
|
void FreeKernelStatus()
|
|
{
|
|
UINT i;
|
|
|
|
kernel_status_inited = false;
|
|
|
|
// Lock release
|
|
for (i = 0;i < NUM_KERNEL_STATUS;i++)
|
|
{
|
|
OSDeleteLock(kernel_status_lock[i]);
|
|
}
|
|
}
|
|
|
|
// Lock the kernel status
|
|
void LockKernelStatus(UINT id)
|
|
{
|
|
// Validate arguments
|
|
if (id >= NUM_KERNEL_STATUS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
OSLock(kernel_status_lock[id]);
|
|
}
|
|
|
|
// Unlock the kernel status
|
|
void UnlockKernelStatus(UINT id)
|
|
{
|
|
// Validate arguments
|
|
if (id >= NUM_KERNEL_STATUS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
OSUnlock(kernel_status_lock[id]);
|
|
}
|
|
|
|
// Display the debug information
|
|
void PrintDebugInformation()
|
|
{
|
|
MEMORY_STATUS memory_status;
|
|
GetMemoryStatus(&memory_status);
|
|
|
|
// Header
|
|
Print("====== " CEDAR_PRODUCT_STR " VPN System Debug Information ======\n");
|
|
|
|
// Memory information
|
|
Print(" <Memory Status>\n"
|
|
" Number of Allocated Memory Blocks: %u\n"
|
|
" Total Size of Allocated Memory Blocks: %u bytes\n",
|
|
memory_status.MemoryBlocksNum, memory_status.MemorySize);
|
|
|
|
// Footer
|
|
Print("====================================================\n");
|
|
|
|
if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
|
|
KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
|
|
{
|
|
// Show a debug menu because memory leaks suspected
|
|
MemoryDebugMenu();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|