1.0.3
This commit is contained in:
parent
690376ef04
commit
36cc77873c
|
@ -7,7 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||
## [1.0.3 / 5.55.3] - 2021-12-??
|
||||
|
||||
### Added
|
||||
- added mechanism to hook Win32 system calls, this should resolve the issue with Chromium HW acceleration
|
||||
- added mechanism to hook Win32 system calls on windows 10 and later, this should resolve the issue with Chromium HW acceleration
|
||||
-- to enable it, add "EnableWin32kHooks=y" to the global ini section, this feature is highly experimental (!)
|
||||
-- the hooks will be automatically applied to Chromium GPU processes
|
||||
-- to force Win32k hooks for all processes in a selected box add "AlwaysUseWin32kHooks=y" [#1261](https://github.com/sandboxie-plus/Sandboxie/issues/1261) [#1395](https://github.com/sandboxie-plus/Sandboxie/issues/1395)
|
||||
|
|
|
@ -441,6 +441,12 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="syscall_util.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="syscall_win32.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieRelease|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='SbieDebug|Win32'">true</ExcludedFromBuild>
|
||||
|
|
|
@ -156,6 +156,9 @@
|
|||
<ClCompile Include="dll.c">
|
||||
<Filter>syscall</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="syscall_util.c">
|
||||
<Filter>syscall</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api.h" />
|
||||
|
|
|
@ -1489,6 +1489,20 @@ _FX NTSTATUS Conf_Api_Reload(PROCESS *proc, ULONG64 *parms)
|
|||
Token_Init_SbieLogin();
|
||||
}
|
||||
|
||||
/*
|
||||
#ifdef HOOK_WIN32K
|
||||
// must be windows 10 or later
|
||||
if (Driver_OsBuild >= 10041) {
|
||||
extern ULONG Syscall_MaxIndex32;
|
||||
if (Conf_Get_Boolean(NULL, L"EnableWin32kHooks", 0, FALSE) && Syscall_MaxIndex32 == 0) {
|
||||
if(Syscall_Init_List32()){
|
||||
Syscall_Init_Table32();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
|
||||
InterlockedExchange(&reconf_lock, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "util.h"
|
||||
#include "session.h"
|
||||
#include "conf.h"
|
||||
|
||||
#include "common/pattern.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -101,6 +101,7 @@ static BOOLEAN Syscall_GetKernelAddr(
|
|||
#pragma alloc_text (INIT, Syscall_GetServiceTable)
|
||||
#endif // ALLOC_PRAGMA
|
||||
|
||||
#include "syscall_util.c"
|
||||
|
||||
#ifdef HOOK_WIN32K
|
||||
#include "syscall_win32.c"
|
||||
|
@ -267,6 +268,7 @@ _FX BOOLEAN Syscall_Init(void)
|
|||
|
||||
_FX BOOLEAN Syscall_Init_List(void)
|
||||
{
|
||||
BOOLEAN success = FALSE;
|
||||
UCHAR *name, *ntdll_code;
|
||||
void *ntos_addr;
|
||||
DLL_ENTRY *dll;
|
||||
|
@ -276,17 +278,26 @@ _FX BOOLEAN Syscall_Init_List(void)
|
|||
|
||||
List_Init(&Syscall_List);
|
||||
|
||||
//
|
||||
// preapre the enabled/disabled lists
|
||||
//
|
||||
|
||||
//LIST enabled_hooks;
|
||||
//LIST disabled_hooks;
|
||||
//Syscall_LoadHookMap(L"EnableNtDllHook", &enabled_hooks);
|
||||
//Syscall_LoadHookMap(L"DisableNtDllHook", &disabled_hooks);
|
||||
|
||||
//
|
||||
// scan each ZwXxx export in NTDLL
|
||||
//
|
||||
|
||||
dll = Dll_Load(Dll_NTDLL);
|
||||
if (! dll)
|
||||
return FALSE;
|
||||
goto finish;
|
||||
|
||||
proc_offset = Dll_GetNextProc(dll, "Zw", &name, &proc_index);
|
||||
if (! proc_offset)
|
||||
return FALSE;
|
||||
goto finish;
|
||||
|
||||
while (proc_offset) {
|
||||
|
||||
|
@ -321,12 +332,18 @@ _FX BOOLEAN Syscall_Init_List(void)
|
|||
|| IS_PROC_NAME(18, "TerminateJobObject")
|
||||
|| IS_PROC_NAME(16, "TerminateProcess")
|
||||
|| IS_PROC_NAME(15, "TerminateThread")
|
||||
|| IS_PROC_NAME(14, "YieldExecution") // ICD-10607 - McAfee uses it to pass its own data in the stack. The call is not important to us.
|
||||
|
||||
) {
|
||||
goto next_zwxxx;
|
||||
}
|
||||
|
||||
//BOOLEAN default_action = TRUE;
|
||||
|
||||
// ICD-10607 - McAfee uses it to pass its own data in the stack. The call is not important to us.
|
||||
if ( IS_PROC_NAME(14, "YieldExecution"))
|
||||
goto next_zwxxx;
|
||||
// default_action = FALSE;
|
||||
|
||||
//
|
||||
// the Google Chrome "wow_helper" process expects NtMapViewOfSection
|
||||
// to not be already hooked. although this is needed only on 64-bit
|
||||
|
@ -336,6 +353,17 @@ _FX BOOLEAN Syscall_Init_List(void)
|
|||
|
||||
if ( IS_PROC_NAME(16, "MapViewOfSection"))
|
||||
goto next_zwxxx;
|
||||
// default_action = FALSE;
|
||||
|
||||
//
|
||||
// check our custom map
|
||||
//
|
||||
|
||||
//if (!Syscall_TestHookMap(name, name_len, &enabled_hooks, &disabled_hooks, default_action)) {
|
||||
// //DbgPrint(" NtDll Hook disabled for %s\n", name);
|
||||
// goto next_zwxxx;
|
||||
//}
|
||||
//DbgPrint(" NtDll Hook enabled for %s\n", name);
|
||||
|
||||
//
|
||||
// analyze each ZwXxx export to find the service index number
|
||||
|
@ -368,7 +396,7 @@ _FX BOOLEAN Syscall_Init_List(void)
|
|||
if (! ntos_addr) {
|
||||
|
||||
Syscall_ErrorForAsciiName(name);
|
||||
return FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -378,7 +406,7 @@ _FX BOOLEAN Syscall_Init_List(void)
|
|||
entry_len = sizeof(SYSCALL_ENTRY) + name_len + 1;
|
||||
entry = Mem_AllocEx(Driver_Pool, entry_len, TRUE);
|
||||
if (! entry)
|
||||
return FALSE;
|
||||
goto finish;
|
||||
|
||||
entry->syscall_index = (USHORT)syscall_index;
|
||||
entry->param_count = (USHORT)param_count;
|
||||
|
@ -405,21 +433,28 @@ next_zwxxx:
|
|||
proc_offset = Dll_GetNextProc(dll, NULL, &name, &proc_index);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
//
|
||||
// report an error if we did not find a reasonable number of services
|
||||
//
|
||||
|
||||
if (Syscall_MaxIndex < 100) {
|
||||
Log_Msg1(MSG_1113, L"100");
|
||||
return FALSE;
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
if (Syscall_MaxIndex >= 500) {
|
||||
Log_Msg1(MSG_1113, L"500");
|
||||
return FALSE;
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
finish:
|
||||
|
||||
//Syscall_FreeHookMap(&enabled_hooks);
|
||||
//Syscall_FreeHookMap(&disabled_hooks);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2021 David Xanatos, xanasoft.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Syscall Management
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Functions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Syscall_LoadHookMap
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX BOOLEAN Syscall_LoadHookMap(const WCHAR* setting_name, LIST *list)
|
||||
{
|
||||
ULONG index;
|
||||
const WCHAR *value;
|
||||
PATTERN* pat;
|
||||
|
||||
List_Init(list);
|
||||
|
||||
Conf_AdjustUseCount(TRUE);
|
||||
|
||||
for (index = 0; ; ++index) {
|
||||
|
||||
//
|
||||
// get next configuration setting for this path list
|
||||
//
|
||||
|
||||
value = Conf_Get(NULL, setting_name, index);
|
||||
if (! value)
|
||||
break;
|
||||
|
||||
//
|
||||
// create pattern and add to list
|
||||
//
|
||||
|
||||
pat = Pattern_Create(Driver_Pool, value, FALSE, 0);
|
||||
if (pat) {
|
||||
List_Insert_After(list, NULL, pat);
|
||||
}
|
||||
}
|
||||
|
||||
Conf_AdjustUseCount(FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Syscall_HookMapMatch
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX int Syscall_HookMapMatch(const WCHAR *name, ULONG name_len, LIST *list)
|
||||
{
|
||||
PATTERN* pat;
|
||||
int match_len = 0;
|
||||
|
||||
pat = List_Head(list);
|
||||
while (pat) {
|
||||
|
||||
int cur_len = Pattern_MatchX(pat, name, name_len);
|
||||
if (cur_len > match_len) {
|
||||
match_len = cur_len;
|
||||
}
|
||||
|
||||
pat = List_Next(pat);
|
||||
}
|
||||
|
||||
return match_len;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Syscall_TestHookMap
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX BOOLEAN Syscall_TestHookMap(const UCHAR* name, ULONG name_len, LIST* enabled_hooks, LIST* disabled_hooks, BOOLEAN default_action)
|
||||
{
|
||||
if(disabled_hooks->count == 0 && enabled_hooks->count == 0)
|
||||
return default_action;
|
||||
|
||||
WCHAR wname[68];
|
||||
ULONG i;
|
||||
for (i = 0; i < max(name_len, 64); i++)
|
||||
wname[i] = name[i];
|
||||
wname[i] = 0;
|
||||
|
||||
int disabe_match = Syscall_HookMapMatch(wname, name_len, disabled_hooks);
|
||||
int enable_match = Syscall_HookMapMatch(wname, name_len, enabled_hooks);
|
||||
if (disabe_match >= enable_match)
|
||||
return FALSE;
|
||||
if (enable_match != 0)
|
||||
return TRUE;
|
||||
return default_action;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Syscall_FreeHookMap
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
_FX VOID Syscall_FreeHookMap(LIST *list)
|
||||
{
|
||||
PATTERN* pat;
|
||||
while (1) {
|
||||
pat = List_Head(list);
|
||||
if (! pat)
|
||||
break;
|
||||
List_Remove(list, pat);
|
||||
Pattern_Free(pat);
|
||||
}
|
||||
}
|
|
@ -128,18 +128,36 @@ _FX BOOLEAN Syscall_GetWin32kAddr(ULONG *Base_Copy,
|
|||
|
||||
_FX BOOLEAN Syscall_Init_List32(void)
|
||||
{
|
||||
BOOLEAN success = FALSE;
|
||||
UCHAR *name, *win32k_code;
|
||||
void *ntos_addr;
|
||||
DLL_ENTRY *dll;
|
||||
SYSCALL_ENTRY *entry;
|
||||
ULONG proc_index, proc_offset, syscall_index, param_count;
|
||||
ULONG name_len, entry_len;
|
||||
ULONG* table_copy = NULL;
|
||||
|
||||
List_Init(&Syscall_List32);
|
||||
|
||||
//
|
||||
// preapre the enabled/disabled lists
|
||||
//
|
||||
|
||||
LIST enabled_hooks;
|
||||
LIST disabled_hooks;
|
||||
Syscall_LoadHookMap(L"EnableWin32Hook", &enabled_hooks);
|
||||
Syscall_LoadHookMap(L"DisableWin32Hook", &disabled_hooks);
|
||||
|
||||
//BOOLEAN ignore_hook_blacklist = Conf_Get_Boolean(NULL, L"IgnoreHookBlacklist", 0, FALSE);
|
||||
|
||||
//
|
||||
// get the syscall table
|
||||
//
|
||||
|
||||
KSERVICE_TABLE_DESCRIPTOR *ShadowTable = (KSERVICE_TABLE_DESCRIPTOR *)Syscall_GetServiceTable();
|
||||
if (!ShadowTable) {
|
||||
Log_Msg1(MSG_1113, L"SHADOW_TABLE");
|
||||
return FALSE;
|
||||
goto finish;
|
||||
}
|
||||
//DbgPrint(" win32k.sys SysCalls: %d %p %p\n", ShadowTable->Limit, ShadowTable->Base, ShadowTable->Number);
|
||||
ShadowTable += 1;
|
||||
|
@ -147,26 +165,24 @@ _FX BOOLEAN Syscall_Init_List32(void)
|
|||
|
||||
if (ShadowTable->Limit > 0xFFF) { // not plausible
|
||||
Log_Msg1(MSG_1113, L"SHADOW_TABLE");
|
||||
return FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
//
|
||||
// We can not read ShadowTable->Base bemory, without being in a GUI thread
|
||||
// hence we grab csrss.exe and attache to it, create a copy of this memory
|
||||
// hence we grab csrss.exe and attach to it, create a copy of this memory
|
||||
// and use it in the loop below instead
|
||||
//
|
||||
|
||||
HANDLE csrssId = Util_GetProcessPidByName(L"csrss.exe");
|
||||
if (csrssId == (HANDLE)-1) {
|
||||
Log_Msg1(MSG_1113, L"csrss.exe");
|
||||
return FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ULONG* table_copy = (ULONG*)Mem_AllocEx(Driver_Pool, ShadowTable->Limit * sizeof(long), TRUE);
|
||||
if (!table_copy)
|
||||
return FALSE;
|
||||
|
||||
BOOLEAN success = FALSE;
|
||||
table_copy = (ULONG*)Mem_AllocEx(Driver_Pool, ShadowTable->Limit * sizeof(long), TRUE);
|
||||
if (!table_copy)
|
||||
goto finish;
|
||||
|
||||
PEPROCESS ProcessObject;
|
||||
if (NT_SUCCESS(PsLookupProcessByProcessId(csrssId,&ProcessObject))) {
|
||||
|
@ -182,26 +198,21 @@ _FX BOOLEAN Syscall_Init_List32(void)
|
|||
|
||||
if (!success) {
|
||||
Log_Msg1(MSG_1113, L"WIN32K_TABLE");
|
||||
return FALSE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
//
|
||||
// ready
|
||||
//
|
||||
|
||||
List_Init(&Syscall_List32);
|
||||
success = FALSE;
|
||||
|
||||
//
|
||||
// scan each NtXxx export in WIN32U
|
||||
//
|
||||
|
||||
dll = Dll_Load(L"WIN32U");
|
||||
if (! dll)
|
||||
return FALSE;
|
||||
if (!dll)
|
||||
goto finish;
|
||||
|
||||
proc_offset = Dll_GetNextProc(dll, "Nt", &name, &proc_index);
|
||||
if (! proc_offset)
|
||||
return FALSE;
|
||||
goto finish;
|
||||
|
||||
while (proc_offset) {
|
||||
|
||||
|
@ -221,35 +232,40 @@ _FX BOOLEAN Syscall_Init_List32(void)
|
|||
// with out sys call interface, but also it would be a security issue
|
||||
// to allow user code execution while we have restored the original token
|
||||
//
|
||||
// also some hooks cause BSOD's for now we just blacklist them
|
||||
//
|
||||
|
||||
#define IS_PROC_NAME(ln,nm) (name_len == ln && memcmp(name, nm, ln) == 0)
|
||||
|
||||
/*if ( IS_PROC_NAME(18, "UserCreateWindowEx")
|
||||
|
||||
|| memcmp(name, "User", 4) == 0 // a lot of user stuff breaks genrally
|
||||
|
||||
|| IS_PROC_NAME(27, "UserSetProcessWindowStation") // bsod
|
||||
|| IS_PROC_NAME(15, "UserCallNoParam")
|
||||
|| IS_PROC_NAME(16, "UserCallOneParam")
|
||||
|| IS_PROC_NAME(16, "UserCallTwoParam")
|
||||
|| IS_PROC_NAME(20, "UserSetWindowLongPtr")
|
||||
|| IS_PROC_NAME(33, "UserSetProcessDpiAwarenessContext") // bsod
|
||||
//if(!ignore_hook_blacklist)
|
||||
if ( IS_PROC_NAME(18, "UserCreateWindowEx")
|
||||
|
||||
|| IS_PROC_NAME( 7, "GdiInit") // bsod
|
||||
|| IS_PROC_NAME(12, "GdiInitSpool") // probably too
|
||||
|
||||
|| IS_PROC_NAME(27, "UserSetProcessWindowStation") // bsod
|
||||
|| IS_PROC_NAME(33, "UserSetProcessDpiAwarenessContext") // bsod
|
||||
|| IS_PROC_NAME(20, "UserSetThreadDesktop") // bsod
|
||||
|
||||
) {
|
||||
goto next_ntxxx;
|
||||
}*/
|
||||
|
||||
#define IS_PROC_PREFIX(ln,nm) (name_len >= ln && memcmp(name, nm, ln) == 0)
|
||||
|
||||
if (!IS_PROC_PREFIX(8, "GdiDdDDI")
|
||||
/*&& !IS_PROC_NAME(16, "UserSetCursorPos")*/) {
|
||||
//DbgPrint(" Win32k Hook disabled for %s (blacklisted)\n", name);
|
||||
goto next_ntxxx;
|
||||
}
|
||||
|
||||
#define IS_PROC_PREFIX(ln,nm) (name_len >= ln && memcmp(name, nm, ln) == 0)
|
||||
|
||||
//
|
||||
// Chrome and msedge need GdiDdDDI to be hooked in order for
|
||||
// the HW acceleration to work
|
||||
//
|
||||
|
||||
BOOLEAN default_action = IS_PROC_PREFIX(8, "GdiDdDDI");
|
||||
|
||||
if (!Syscall_TestHookMap(name, name_len, &enabled_hooks, &disabled_hooks, default_action)) {
|
||||
//DbgPrint(" Win32k Hook disabled for %s\n", name);
|
||||
goto next_ntxxx;
|
||||
}
|
||||
//DbgPrint(" Win32k Hook enabled for %s\n", name);
|
||||
|
||||
//
|
||||
// analyze each NtXxx export to find the service index number
|
||||
|
@ -288,7 +304,7 @@ _FX BOOLEAN Syscall_Init_List32(void)
|
|||
if (! ntos_addr) {
|
||||
Syscall_ErrorForAsciiName(name);
|
||||
goto next_ntxxx;
|
||||
//return FALSE;
|
||||
//goto finish;
|
||||
}
|
||||
|
||||
syscall_index = (syscall_index & 0xFFF);
|
||||
|
@ -299,10 +315,8 @@ _FX BOOLEAN Syscall_Init_List32(void)
|
|||
|
||||
entry_len = sizeof(SYSCALL_ENTRY) + name_len + 1;
|
||||
entry = Mem_AllocEx(Driver_Pool, entry_len, TRUE);
|
||||
if (!entry) {
|
||||
Syscall_MaxIndex32 = 0;
|
||||
return FALSE;
|
||||
}
|
||||
if (!entry)
|
||||
goto finish;
|
||||
|
||||
entry->syscall_index = (USHORT)syscall_index;
|
||||
entry->param_count = (USHORT)param_count;
|
||||
|
@ -330,6 +344,8 @@ next_ntxxx:
|
|||
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
//DbgPrint("Found %d win32 SysCalls\n", Syscall_MaxIndex32);
|
||||
|
||||
//
|
||||
|
@ -338,19 +354,26 @@ next_ntxxx:
|
|||
|
||||
if (Syscall_MaxIndex32 < 100) {
|
||||
Log_Msg1(MSG_1113, L"100");
|
||||
Syscall_MaxIndex32 = 0;
|
||||
return FALSE;
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
if (Syscall_MaxIndex32 >= 2000) {
|
||||
Log_Msg1(MSG_1113, L"2000");
|
||||
Syscall_MaxIndex32 = 0;
|
||||
return FALSE;
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
Mem_Free(table_copy, ShadowTable->Limit * sizeof(long));
|
||||
finish:
|
||||
|
||||
return TRUE;
|
||||
if(!success)
|
||||
Syscall_MaxIndex32 = 0;
|
||||
|
||||
Syscall_FreeHookMap(&enabled_hooks);
|
||||
Syscall_FreeHookMap(&disabled_hooks);
|
||||
|
||||
if (table_copy)
|
||||
Mem_Free(table_copy, ShadowTable->Limit * sizeof(long));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue