SHOW:
|
|
- or go back to the newest paste.
| 1 | #include <iostream> | |
| 2 | #include <strsafe.h> | |
| 3 | #include <wtypes.h> | |
| 4 | #include <winnt.h> | |
| 5 | ||
| 6 | typedef _Return_type_success_(return >= 0) LONG NTSTATUS; | |
| 7 | #define NT_SUCCESS(Status) (((NTSTATUS)(Status) >= 0)) | |
| 8 | #define OBJ_CASE_INSENSITIVE 0x00000040L | |
| 9 | ||
| 10 | typedef struct _UNICODE_STRING | |
| 11 | {
| |
| 12 | USHORT Length; | |
| 13 | USHORT MaximumLength; | |
| 14 | PWSTR Buffer; | |
| 15 | } UNICODE_STRING, * PUNICODE_STRING; | |
| 16 | ||
| 17 | typedef struct _OBJECT_ATTRIBUTES | |
| 18 | {
| |
| 19 | ULONG Length; | |
| 20 | HANDLE RootDirectory; | |
| 21 | PUNICODE_STRING ObjectName; | |
| 22 | ULONG Attributes; | |
| 23 | PVOID SecurityDescriptor; | |
| 24 | PVOID SecurityQualityOfService; | |
| 25 | } OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; | |
| 26 | ||
| 27 | template< typename modHandleType, typename procNameType > | |
| 28 | auto getProcAddressOrThrow(modHandleType modHandle, procNameType procName) {
| |
| 29 | auto address = GetProcAddress(modHandle, procName); | |
| 30 | if (address == nullptr) throw std::exception{ (std::string{"Error importing: "} + (std::string{procName})).c_str() };
| |
| 31 | return address; | |
| 32 | } | |
| 33 | ||
| 34 | #define CONCAT( id1, id2 ) id1##id2 | |
| 35 | // Notice- the comma operator is used to make sure the dll is loaded, discard the result- then getModuleHandle is used | |
| 36 | ||
| 37 | #define IMPORTAPI( DLLFILE, FUNCNAME, RETTYPE, ... ) \ | |
| 38 | typedef RETTYPE( WINAPI* CONCAT( t_, FUNCNAME ) )( __VA_ARGS__ ); \ | |
| 39 | template< typename... Ts > \ | |
| 40 | auto FUNCNAME( Ts... ts ) { \
| |
| 41 | const static CONCAT( t_, FUNCNAME ) func = \ | |
| 42 | (CONCAT( t_, FUNCNAME )) getProcAddressOrThrow( ( LoadLibrary( DLLFILE ), GetModuleHandle( DLLFILE ) ), #FUNCNAME ); \ | |
| 43 | return func( std::forward< Ts >( ts )... ); \ | |
| 44 | }; | |
| 45 | ||
| 46 | IMPORTAPI(L"ntdll.dll", RtlNtStatusToDosError, NTSTATUS, NTSTATUS ) | |
| 47 | IMPORTAPI( L"ntdll.dll", NtCreateSymbolicLinkObject, NTSTATUS, PHANDLE , ACCESS_MASK , POBJECT_ATTRIBUTES , PUNICODE_STRING ) | |
| 48 | ||
| 49 | void ErrorExit(LPTSTR lpszFunction,NTSTATUS ntstatus) | |
| 50 | {
| |
| 51 | LPVOID lpMsgBuf; | |
| 52 | LPVOID lpDisplayBuf; | |
| 53 | DWORD dw = RtlNtStatusToDosError(ntstatus) ; | |
| 54 | ||
| 55 | FormatMessage( | |
| 56 | FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
| 57 | FORMAT_MESSAGE_FROM_SYSTEM | | |
| 58 | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 59 | NULL, | |
| 60 | dw, | |
| 61 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| 62 | (LPTSTR)&lpMsgBuf, | |
| 63 | 0, NULL); | |
| 64 | ||
| 65 | lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); | |
| 66 | StringCchPrintf( (LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf );
| |
| 67 | ||
| 68 | MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
| |
| 69 | ||
| 70 | LocalFree(lpMsgBuf); | |
| 71 | LocalFree(lpDisplayBuf); | |
| 72 | ExitProcess(dw); | |
| 73 | } | |
| 74 | ||
| 75 | int main() | |
| 76 | {
| |
| 77 | HANDLE SymbolicLinkHandle; | |
| 78 | UNICODE_STRING dest{ 8, 8, []() { static auto dest = (wchar_t*)L"\\NUL"; return dest; }() };
| |
| 79 | ||
| 80 | UNICODE_STRING link{ 28, 28, []() { static auto dest = (wchar_t*)L"\\??\\GLOBALROOT"; return dest; }() };
| |
| 81 | OBJECT_ATTRIBUTES oa{ sizeof(OBJECT_ATTRIBUTES), 0, &link, OBJ_CASE_INSENSITIVE, nullptr, nullptr };
| |
| 82 | ||
| 83 | auto symlink_status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle, MAXIMUM_ALLOWED, &oa, &dest ); | |
| 84 | if ( ! (NT_SUCCESS(symlink_status))) { ErrorExit((wchar_t*)L"NtCreateSymbolicLinkObject", symlink_status); };
| |
| 85 | ||
| 86 | std::cout << "Created \\??\\GLOBALROOT -> \\NUL - Immunity archived" << std::endl; | |
| 87 | ||
| 88 | system("pause");
| |
| 89 | } |