Last active
September 16, 2020 12:52
-
-
Save CarlTBarnes/d0f94d5ec6df1d4385909d67dbf49bd2 to your computer and use it in GitHub Desktop.
DEP Policy View and Test in Clarion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!DEP Policy Test by Carl Barnes released under the MIT License | |
!C11.13620 has a new Project DEP setting. This does NOT require 13620 | |
!You do NOT need the new 13620 DEP Project setting to turn on DEP, just call SetProcessDEPPolicy(1) | |
!You can add this procedure in your application to check DEP status at runtime on the end user machine. | |
!It probably should be wrapped in a simple CLASS. | |
! | |
!FYI - DEP sets the IMAGE_DLLCHARACTERISTICS_NX_COMPAT bit in the IMAGE_OPTIONAL_HEADER‘s DllCharacteristics. | |
!-------------------------------------------------------------------------------------- | |
!Must DEP be turned On in Both EXE and DLL projects? NO. Only the EXE the project. | |
! It is suggested to turn on DEP in the DLL as an FYI it works with DEP. | |
! IMO this is not needed for Clarion DLLs you build to consume in your own projects. | |
! | |
!Above based on The OldNewThing Raymond Chen says the DEP setting only matters for the EXE and Process | |
!Setting it on the DLL has no affect | |
!https://devblogs.microsoft.com/oldnewthing/20170607-00/?p=96295 | |
! | |
! Are there any adverse consequences of mixing NX-enabled DLLs and non-NX-enabled DLLs in the same process? | |
! The NX setting (DEP) is process-wide, and the process takes its NX state from | |
! the /NXENABLED state of the executable, not from any DLLs. It’s yet another | |
! one of the module flags that are meaningless for DLLs. | |
! https://devblogs.microsoft.com/oldnewthing/20140502-00/?p=1093 | |
! LARGEADDRESSAWARE SizeOfStackReserve SizeOfStackCommit | |
! So mix it up in the DLLs all you want. Nobody will care, because the flag is ignored for DLLs anyway. | |
!-------------------------------------------------------------------------------------- | |
PROGRAM | |
INCLUDE('KEYCODES.CLW') | |
MAP | |
DepPolicyTest PROCEDURE() | |
DEP_GPF_Test PROCEDURE() | |
GetLastErrorMessage PROCEDURE(long GetLastErrorCode),STRING | |
MODULE('Win32') | |
CloseHandle(LONG HANDLE),BOOL,PASCAL,PROC,DLL(1) | |
FormatMessage(LONG dwFlags, LONG lpSource, LONG dwMessageId, LONG dwLanguageId, *CSTRING lpBuffer, LONG nSize, LONG VA_List=0),LONG,PASCAL,RAW,DLL(1),NAME('FormatMessageA') !Returns Char count | |
GetProcessDEPPolicy(SIGNED hProcess, *UNSIGNED lpFlags, *BOOL lpPermanent ),BOOL,PASCAL,DLL(1) | |
SetProcessDEPPolicy(UNSIGNED lpFlags),BOOL,PROC,PASCAL,DLL(1) !(1)=DEP Enable if System optIN, (0)=Off if System OptOut | |
GetSystemDEPPolicy(),LONG,PASCAL,DLL(1) | |
GetLastError(),LONG,PASCAL,DLL(1) | |
GetCurrentProcess(),LONG,PASCAL,DLL(1) | |
OpenProcess(LONG dwDesiredAccess, BOOL bInheritHandle, LONG dwProcessId),LONG,PASCAL,DLL(1) | |
OutputDebugString(*CSTRING cMsg),PASCAL,DLL(1),RAW,NAME('OutputDebugStringA') | |
VirtualAlloc(LONG lpAddress, LONG dwSize, LONG flAllocationType, LONG flProtect ),LONG,PASCAL,DLL(1) | |
MemCpy(LONG DestAddr,LONG SourceAddr,Unsigned Bytes2Copy),LONG,NAME('_memcpy'),PROC,DLL(Dll_Mode) | |
ShellCodeTest PROCEDURE(),DLL(_fp_),PASCAL,NAME('ShellCodeTestExec') | |
END | |
END | |
ShellCodeTest_fp LONG,NAME('ShellCodeTestExec') | |
PROCESS_DEP_ENABLE EQUATE(1) !DEP is enabled for the specified process. | |
PROCESS_DEP_DISABLE_ATL_THUNK EQUATE(2) !DEP-ATL thunk emulation is disabled for the specified process. For information about DEP-ATL thunk emulation, see SetProcessDEPPolicy. | |
CODE | |
SYSTEM{7A7Dh}=MSGMODE:CANCOPY !PROP:MsgModeDefault | |
DepPolicyTest() | |
DepPolicyTest PROCEDURE() | |
Ndx LONG,AUTO | |
GLE LONG,AUTO | |
SystemDepPolicy LONG | |
SysDepOption BYTE !DepSystem + 1 | |
ProDep_Hnd LONG | |
ProDep_Flags LONG | |
ProDep_Perm LONG | |
ProDep_BOOL LONG | |
ProcessDep STRING(255) | |
ProcessPerm STRING(255) | |
DepEnableResult STRING(255) | |
DepDisableResult STRING(255) | |
Window WINDOW('DEP Policy View and Test'),AT(,,395,260),GRAY,SYSTEM,ICON(ICON:Frame),FONT('Segoe UI',9) | |
STRING('GetSystemDEPPolicy(),LONG'),AT(88,4),USE(?GetDepSysPrototype),FONT('Consolas',10) | |
ENTRY(@s3),AT(194,4,,10),USE(SystemDepPolicy),SKIP,CENTER,FONT('Consolas'),READONLY | |
OPTION('System DEP Policy'),AT(7,4,70,68),USE(SysDepOption),BOXED | |
RADIO('Always OFF'),AT(14,15),USE(?SysDepOpt:RADIO1) | |
RADIO('Always ON'),AT(14,26),USE(?SysDepOpt:RADIO2) | |
RADIO('Opt IN'),AT(14,36),USE(?SysDepOpt:RADIO3) | |
RADIO('Opt OUT'),AT(14,47),USE(?SysDepOpt:RADIO4) | |
RADIO('Unknown'),AT(14,58),USE(?SysDepOpt:RADIO5) | |
END | |
BUTTON('Change System DEP'),AT(359,4,32,32),USE(?ChangeSysDepBtn) | |
PROMPT('System DEP Tip'),AT(88,18,265,54),USE(?SystemDepTIP) | |
PANEL,AT(7,83,382,2),USE(?HorzLine1),BEVEL(0,0,0600H) | |
STRING('GetProcessDEPPolicy(LONG hProcess, *LONG OutFlags, *BOOL Permanent),BOOL'),AT(7,90),USE(?GetDepProPrototype), | | |
FONT('Consolas',10) | |
ENTRY(@s9),AT(89,101,,10),USE(ProDep_Hnd),SKIP,CENTER,FONT('Consolas'),READONLY | |
ENTRY(@s9),AT(152,101,,10),USE(ProDep_Flags),SKIP,CENTER,FONT('Consolas'),READONLY | |
ENTRY(@s9),AT(218,101,,10),USE(ProDep_Perm),SKIP,CENTER,FONT('Consolas'),READONLY | |
ENTRY(@s9),AT(278,101,,10),USE(ProDep_BOOL),SKIP,CENTER,FONT('Consolas'),READONLY | |
STRING('Process DEP:'),AT(7,121),USE(?ProcessDep:Pmt) | |
ENTRY(@s255),AT(51,119,335,11),USE(ProcessDep),SKIP,READONLY | |
STRING('Permanent:'),AT(7,134),USE(?Permanent:Pmt) | |
ENTRY(@s255),AT(51,133,335,11),USE(ProcessPerm),SKIP,READONLY | |
BUTTON('SetProcessDEPPolicy(1) - Enable'),AT(7,151,142,14),USE(?DepEnableBtn),FONT('Consolas',10),LEFT | |
BUTTON('SetProcessDEPPolicy(0) - Disable'),AT(7,170,142,14),USE(?DepDisableBtn),FONT('Consolas',10),LEFT | |
STRING(@s255),AT(157,153),USE(DepEnableResult) | |
STRING(@s255),AT(157,172),USE(DepDisableResult) | |
BUTTON('GPF<13,10>with<13,10>DEP'),AT(359,151,28,32),USE(?GpfWithDepBtn),TIP('Execute Shell Code in a Data Page that shows Message(Hello World).' & | | |
'<13,10>This will GPF if DEP is Enabled.<13,10>This will always shutdown this program after the message.') | |
PANEL,AT(7,191,382,2),USE(?HorzLine2),BEVEL(0,0,0600H) | |
PROMPT('Clarion 13602 added a new Project “DEP” setting on the Compile tab to turn ON the DEP Flag in the EXE He' & | | |
'ader (NX COMPAT Dll Characteristics). If DEP is ON in the EXE Header then your process will have DEP En' & | | |
'abled (Permanent) as long as the System DEP Policy is not "Always Off". The DLL project DEP does NOT m' & | | |
'atter, only the EXE. <13,10><13,10>If you leave DEP Off in the EXE project you can selectively Enable it f' & | | |
'or your process by calling SetProcessDEPPolicy(1). <13,10>This tool allows trying settings and API calls to se' & | | |
'e the resulting Process DEP Policy using GetProcessDEPPolicy().'),AT(7,198,377,54),USE(?DEPInfo) | |
END | |
DOO CLASS | |
GetSystemDep PROCEDURE() | |
GetProcessDep PROCEDURE() | |
SetProcessDep PROCEDURE(BYTE Enable, *STRING ResultString) | |
SetupWindow PROCEDURE() | |
END | |
CODE | |
DepEnableResult='Click button to see result of Enable. Usually can only do once.' | |
DepDisableResult='Click to Disable DEP. Use with "Opt Out" Policy on Servers.' | |
OPEN(Window) | |
LOOP Ndx=FIRSTFIELD() TO LASTFIELD() | |
IF Ndx{PROP:ReadOnly} AND Ndx{PROP:Type}=CREATE:Entry THEN | |
Ndx{PROP:Background}=COLOR:GradientInactiveCaption | |
Ndx{PROP:FontColor} =COLOR:CAPTIONTEXT | |
END | |
END | |
DOO.SetupWindow() | |
!Test ?SysDepOption{PROP:ReadOnly}=0 !Let click on System policy show text | |
ACCEPT | |
CASE EVENT() | |
OF EVENT:OpenWindow | |
END | |
CASE ACCEPTED() | |
OF ?ChangeSysDepBtn | |
IF Message('To Change System DEP Policy:' & | | |
'||Open System Properties (SystemPropertiesAdvanced.exe)' & | | |
'|Select Advanced Tab' & | | |
'|Click Performace group Settings button' & | | |
'|Click Data Execution Prevention tab' & | | |
'||This same window has "Environment Variables",|which is easier to search for under Start.', | | |
'Change System DEP Setting',,'Close|Run System Props')=2 THEN | |
RUN('SystemPropertiesAdvanced.exe') !Surprized this does not need elevation | |
IF ERRORCODE() THEN | |
MESSAGE('Run Error ' & ErrorCode()&' '&ERROR()) | |
END | |
END !if | |
OF ?SysDepOption ; ?SystemDepTIP{PROP:Text}=(?+SysDepOption){PROP:Tip} !Test | |
OF ?DepEnableBtn ; DOO.SetProcessDep(1,DepEnableResult) | |
OF ?DepDisableBtn ; DOO.SetProcessDep(0,DepDisableResult) | |
OF ?GpfWithDepBtn ; DEP_GPF_Test() | |
END | |
CASE FIELD() | |
END | |
END | |
DOO.SetProcessDep PROCEDURE(BYTE Enable, *STRING ResultString) | |
CODE | |
IF SetProcessDEPPolicy(Enable) THEN | |
ResultString=CHOOSE(~Enable,'Disable','Enable') &' Success!' | |
ELSE | |
GLE=GetLastError() | |
ResultString='Error ' & GLE &' '& GetLastErrorMessage(GLE) | |
END | |
DOO.GetProcessDep() | |
DISPLAY | |
RETURN | |
DOO.GetProcessDep PROCEDURE() | |
CODE | |
ProDep_Hnd = GetCurrentProcess() | |
ProDep_BOOL = GetProcessDEPPolicy(ProDep_Hnd,ProDep_Flags,ProDep_Perm) | |
IF ~ProDep_BOOL THEN | |
GLE=GetLastError() | |
ProcessDep='Error ' & GLE &' - '& GetLastErrorMessage(GLE) | |
ProcessPerm='' | |
RETURN | |
END | |
IF ProDep_Flags=0 THEN | |
ProcessDep='DEP is DISABLED for this Process' | |
ELSE | |
IF BAND(ProDep_Flags,PROCESS_DEP_ENABLE) THEN | |
ProcessDep='DEP is ENABLED for this Process' & | | |
CHOOSE(~BAND(ProDep_Flags,PROCESS_DEP_DISABLE_ATL_THUNK),'',' + DEP-ATL thunk emulation is disabled') | |
ELSIF BAND(ProDep_Flags,PROCESS_DEP_DISABLE_ATL_THUNK) THEN !I don't care, should not see in Clarion | |
ProcessDep='DEP-ATL thunk emulation is disabled for the specified process.' | |
!It should not happen that this is alone | |
ELSE | |
ProcessDep='Unknown DEP Policy Flags: ' & ProDep_Flags | |
END | |
END | |
IF ProDep_Perm | |
ProcessPerm='DEP setting is Permanent and CANNOT be changed with SetProcessDEPPolicy()' | |
ELSE | |
ProcessPerm='DEP setting is Not Permanent so can be changed with SetProcessDEPPolicy()' | |
END | |
RETURN | |
! lpPermanent | |
! | |
!TRUE if DEP is enabled or disabled permanently for the specified process; otherwise FALSE. If lpPermanent is TRUE, the current DEP setting persists for the life of the process and cannot be changed by calling SetProcessDEPPolicy. | |
!PROCESS_DEP_ENABLE EQUATE(1) !DEP is enabled for the specified process. | |
!PROCESS_DEP_DISABLE_ATL_THUNK EQUATE(2) !DEP-ATL thunk emulation is disabled for the specified process. For information about DEP-ATL thunk emulation, see SetProcessDEPPolicy. | |
DOO.SetupWindow PROCEDURE() | |
CODE | |
DOO.GetSystemDep() | |
DOO.GetProcessDep() | |
DOO.GetSystemDep PROCEDURE() | |
CODE | |
?SysDepOpt:RADIO1{PROP:Tip} = 'DEP is Disabled for ALL parts of the system and all applications, <13,10>regardless of hardware support for DEP. ' &| | |
'<13,10>The processor runs in PAE mode with 32-bit versions of Windows ' &| | |
'<13,10>unless PAE is disabled in the boot configuration data.' | |
?SysDepOpt:RADIO2{PROP:Tip} = 'DEP is enabled for ALL parts of the system. ' &| | |
'<13,10>All processes always run with DEP enabled. ' &| | |
'<13,10>DEP cannot be explicitly disabled for selected applications. ' &| | |
'<13,10>System compatibility fixes are ignored.' | |
?SysDepOpt:RADIO3{PROP:Tip} = 'On systems with processors that are capable of hardware-enforced DEP, ' &| | |
'<13,10>DEP is automatically ENABLED for Windows OS components ONLY. ' &| | |
'<13,10>This is the default setting for client (desktop) versions of Windows. ' &| | |
'<13,10><13,10>DEP can be explicitly enabled for selected applications or ' &| | |
'<13,10>for the current process by calling SetProcessDEPPolicy(1).' | |
?SysDepOpt:RADIO4{PROP:Tip} = 'DEP is automatically ENABLED for Windows OS components and ALL processes. ' &| | |
'<13,10>This is the default setting for Windows Server versions. ' &| | |
'<13,10><13,10>DEP can be explicitly disabled for selected applications or ' &| | |
'<13,10>for the current process by calling SetProcessDEPPolicy(0).' &| | |
'<13,10>System compatibility fixes for DEP are in effect.' | |
?SysDepOpt:RADIO5{PROP:Tip}='An unknown value was returned by GetSystemDEPPolicy' | |
SystemDepPolicy=GetSystemDEPPolicy() | |
?SysDepOption{PROP:Tip}='GetSystemDEPPolicy() returned ' & SystemDepPolicy | |
IF SystemDepPolicy >= 0 AND SystemDepPolicy <= 3 THEN | |
SysDepOption = SystemDepPolicy + 1 | |
ELSE | |
SysDepOption = 5 | |
?SysDepOpt:RADIO5{PROP:Tip}='GetSystemDEPPolicy() returned "' & SystemDepPolicy &'" an unknown value' | |
END | |
?SystemDepTIP{PROP:Text}=(?SysDepOption+SysDepOption){PROP:Tip} | |
LOOP Ndx=1 TO 5 | |
IF Ndx<>SysDepOption THEN | |
(?SysDepOption+Ndx){PROP:FontColor}=COLOR:GRAYTEXT !Make Look Disabled | |
END | |
END | |
?ProDep_Hnd{PROP:Tip}='A handle to the process with PROCESS_QUERY_INFORMATION privilege is required.<13,10>GetCurrentProcess() returns handle for this process.' | |
?ProDep_Flags{PROP:Tip}= '0=DISBALED = DEP is disabled for the specified process.' &| | |
'<13,10>' &| | |
'<13,10>1=PROCESS_DEP_ENABLE = DEP is enabled for the specified process.' &| | |
'<13,10>' &| | |
'<13,10>2=PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION (Always with Dep Enable)' &| | |
'<13,10>' &| | |
'<13,10>DEP-ATL thunk emulation is disabled for the specified process which prevents ' &| | |
'<13,10>the system from intercepting NX faults that originate from the Active Template Library.' | |
?ProDep_Perm{PROP:Tip} = 'TRUE if DEP is enabled or disabled permanently for the specified process; ' &| | |
'<13,10>FALSE if not permanent and may be changed by SetProcessDEPPolicy. ' &| | |
'<13,10>' &| | |
'<13,10>If lpPermanent is TRUE, the current DEP setting persists for the life of ' &| | |
'<13,10>the process and cannot be changed by calling SetProcessDEPPolicy.' | |
?ProDep_BOOL{PROP:Tip} = 'TRUE if the function succeeds.' &| | |
'<13,10>' &| | |
'<13,10>FALSE if the function Fails. ' &| | |
'<13,10>Call GetLastError() to retrieve error value.' | |
?DepEnableBtn{PROP:Tip}='Enables DEP permanently on the current process.' & | | |
'<13,10>After DEP has been enabled for the process ' & | | |
'<13,10>by setting SetProcessDEPPolicy( PROCESS_DEP_ENABLE ), ' & | | |
'<13,10>it cannot be disabled for the life of the process.' & | | |
'<13,10><13,10>Fails if DEP policy was specified at process creation ' & | | |
'<13,10>by either EXE Header flag or Windows setting for application. ' | |
?DepDisableBtn{PROP:Tip}='If the DEP System Policy is OptIn or OptOut ' & | | |
'<13,10>and DEP is enabled for the process, ' & | | |
'<13,10>setting dwFlags to 0 disables DEP for the process.' | |
RETURN | |
!------------------------------ | |
GetLastErrorMessage PROCEDURE(long GetLastErrorCode)!,string | |
dwLength LONG,AUTO | |
cMsgBuf CSTRING(512) | |
CODE | |
IF GetLastErrorCode THEN !From_System, Ignore_Inserts, Max_Width_Mask | |
dwLength = FormatMessage(12FFh,0,GetLastErrorCode,0,cMsgBuf,SIZE(cMsgBuf)-1) | |
end | |
RETURN CLIP(cMsgBuf) | |
!------------------------------ | |
DEP_GPF_Test PROCEDURE() | |
SC STRING('<066h,081h,0E4h,0FCh,0FFh,031h,0F6h,056h,064h,08Bh,076h,030h,08Bh,076h,00Ch,08Bh>'&| | |
'<076h,01Ch,08Bh,06Eh,008h,08Bh,036h,08Bh,05Dh,03Ch,08Bh,05Ch,01Dh,078h,001h,0EBh>'&| | |
'<08Bh,04Bh,018h,067h,0E3h,0ECh,08Bh,07Bh,020h,001h,0EFh,08Bh,07Ch,08Fh,0FCh,001h>'&| | |
'<0EFh,031h,0C0h,099h,032h,017h,066h,0C1h,0CAh,001h,0AEh,075h,0F7h,066h,081h,0FAh>'&| | |
'<02Ah,0B6h,074h,009h,066h,081h,0FAh,0AAh,01Ah,0E0h,0DBh,075h,0C5h,08Bh,053h,024h>'&| | |
'<001h,0EAh,00Fh,0B7h,014h,04Ah,08Bh,07Bh,01Ch,001h,0EFh,003h,02Ch,097h,085h,0F6h>'&| | |
'<074h,015h,068h,033h,032h,020h,020h,068h,075h,073h,065h,072h,054h,0FFh,0D5h,095h>'&| | |
'<031h,0F6h,0E9h,0A0h,0FFh,0FFh,0FFh,056h,068h,072h,06Ch,064h,021h,068h,06Fh,020h>'&| | |
'<077h,06Fh,068h,048h,065h,06Ch,06Ch,054h,087h,004h,024h,050h,050h,056h,0FFh,0D5h>'&| | |
'<0CCh>') | |
Exec LONG | |
PAGE_READWRITE EQUATE(04) | |
PAGE_EXECUTE_READWRITE EQUATE(40h) !Use this to let the code work with DEP turned on | |
MEM_COMMIT EQUATE(1000h) | |
CODE | |
! SETCLIPBOARD(SC) ; message('sc on clip') | |
!! Exec = VirtualAlloc(0, size(SC), MEM_COMMIT, PAGE_EXECUTE_READWRITE) <-DEP ok if Execute ON | |
Exec = VirtualAlloc(0, size(SC), MEM_COMMIT, PAGE_READWRITE) | |
memcpy(exec, ADDRESS(SC), SIZE(SC)) | |
ShellCodeTest_fp = Exec | |
ShellCodeTest() | |
!Above code from: http://0xdabbad00.com/2012/12/07/dep-data-execution-prevention-explanation/ | |
! | |
!#include <windows.h> | |
! | |
!int main(int argc, char **argv) { | |
! char shellcode[] = { | |
! 0x66, 0x81, 0xE4, 0xFC, 0xFF, 0x31, 0xF6, 0x56, 0x64, 0x8B, 0x76, 0x30, 0x8B, 0x76, 0x0C, 0x8B, | |
! 0x76, 0x1C, 0x8B, 0x6E, 0x08, 0x8B, 0x36, 0x8B, 0x5D, 0x3C, 0x8B, 0x5C, 0x1D, 0x78, 0x01, 0xEB, | |
! 0x8B, 0x4B, 0x18, 0x67, 0xE3, 0xEC, 0x8B, 0x7B, 0x20, 0x01, 0xEF, 0x8B, 0x7C, 0x8F, 0xFC, 0x01, | |
! 0xEF, 0x31, 0xC0, 0x99, 0x32, 0x17, 0x66, 0xC1, 0xCA, 0x01, 0xAE, 0x75, 0xF7, 0x66, 0x81, 0xFA, | |
! 0x2A, 0xB6, 0x74, 0x09, 0x66, 0x81, 0xFA, 0xAA, 0x1A, 0xE0, 0xDB, 0x75, 0xC5, 0x8B, 0x53, 0x24, | |
! 0x01, 0xEA, 0x0F, 0xB7, 0x14, 0x4A, 0x8B, 0x7B, 0x1C, 0x01, 0xEF, 0x03, 0x2C, 0x97, 0x85, 0xF6, | |
! 0x74, 0x15, 0x68, 0x33, 0x32, 0x20, 0x20, 0x68, 0x75, 0x73, 0x65, 0x72, 0x54, 0xFF, 0xD5, 0x95, | |
! 0x31, 0xF6, 0xE9, 0xA0, 0xFF, 0xFF, 0xFF, 0x56, 0x68, 0x72, 0x6C, 0x64, 0x21, 0x68, 0x6F, 0x20, | |
! 0x77, 0x6F, 0x68, 0x48, 0x65, 0x6C, 0x6C, 0x54, 0x87, 0x04, 0x24, 0x50, 0x50, 0x56, 0xFF, 0xD5, | |
! 0xCC | |
! }; | |
! | |
! // works--> void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_EXECUTE_READWRITE); // Works because of EXECUTE | |
! void *exec = VirtualAlloc(0, sizeof shellcode, MEM_COMMIT, PAGE_READWRITE); | |
! memcpy(exec, shellcode, sizeof shellcode); | |
! ((void(*)())exec)(); | |
!} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment