d173220523 发表于 2020-7-2 17:25

为什么这个程序向notepad第二个节后面加入shellcode代码会失败

本帖最后由 d173220523 于 2020-7-2 17:29 编辑

#include "iostream"
#include <windows.h>

#define size_shellcode 0x12
#define messagebox_add 0x77d507ea
BYTE shellcode[] = {
      0x6A,00,0x6A,00,0x6A,00,0x6A,00,
      0XE8,00,00,00,00,
      0XE9,00,00,00,00
};

char file_path[] = "C:\\WINDOWS\\system32\\notepad.exe";
char write_file_path[] = "C:\\notepad1.exe";

// exe->filebuffer返回值为计算所得文件大小
int ReadPEFile(char* file_path,PVOID* pFileBuffer)
{
      FILE* pfile = NULL;// 文件指针
      DWORD file_size = 0;
      LPVOID pTempFilebuffer = NULL;
      
      // 打开文件
      pfile = fopen(file_path,"rb");// 如果有新的指针,就要进行判断
      if(!pfile)
      {
                printf("打开exe文件失败!\n");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
                return 0;
      }      
      // 读取文件大小
      fseek(pfile,0,SEEK_END);
      file_size = ftell(pfile);
      fseek(pfile,0,SEEK_SET);
      // 分配空间
      pTempFilebuffer = malloc(file_size);// 如果有新的指针,就要进行判断
      if(!pTempFilebuffer)
      {
                printf("分配空间失败!\n");//如果分配失败就要关闭文件、释放动态内存、指针指向NULL
                fclose(pfile);
                return 0 ;
      }
      // 将数据读取到内存中
      size_t n = fread(pTempFilebuffer,file_size,1,pfile);
      if(!n)
      {
                printf("数据读取到内存中失败!\n"); //如果分配失败就要关闭文件、释放动态内存、指针指向NULL
                fclose(pfile);
                free(pTempFilebuffer);
                return 0 ;
      }
      // 关闭文件(已经读取到内存了)
      *pFileBuffer = pTempFilebuffer;
      pTempFilebuffer = NULL;
      fclose(pfile);
      return file_size;
}

// filebuffer -> imagebuffer
DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer,PVOID* pImageBuffer)
{
      // 初始化PE头部结构体
      PIMAGE_DOS_HEADER pDosHeader = NULL;      
      PIMAGE_NT_HEADERS pNTHeader = NULL;      
      PIMAGE_FILE_HEADER pPEHeader = NULL;      
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;
      // 初始化IMAGE_BUFFER指针(temparay)
      LPVOID pTempImagebuffer = NULL;

      if(!pFileBuffer)
      {
                printf("(2pimagebuffer阶段)读取到内存的pfilebuffer无效!\n");
                return 0 ;
      }
      // 判断是否是可执行文件
      if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)// IMAGE_DOS_SIGNATURE是4字节,将pFileBuffer强制类型转换为4字节指针类型(PWORD)
      {
                printf("(2pimagebuffer阶段)不含MZ标志,不是exe文件!\n");
                return 0;
      }
      //强制结构体类型转换pDosHeader
      pDosHeader = PIMAGE_DOS_HEADER(pFileBuffer);
      //判断是否含有PE标志      
      if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) // 注意指针的加法是:去掉一个*后的类型相加。必须转换为DWORD类型再加减。
      {                                                                                                                                                          //相加后的和 强制类型转换为4字节指针类型(PWORD) IMAGE_NT_SIGNATURE 4BYTES
                printf("(2pimagebuffer阶段)不是有效的PE标志!\n");      
                return 0;
      }
      // 强制结构体类型转换
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+pDosHeader->e_lfanew);
      pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);

      // 分配动态内存
      pTempImagebuffer = malloc(pOptionHeader->SizeOfImage);
      if(!pTempImagebuffer)
      {
                printf("分配动态内存失败!\n");
                free(pTempImagebuffer);
                return 0;
      }
      // 初始化动态内存
      memset(pTempImagebuffer,0,pOptionHeader->SizeOfImage);
      // 拷贝头部
      memcpy(pTempImagebuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
      // 循环拷贝节表
      PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
      for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++)
      {
                memcpy((void*)((DWORD)pTempImagebuffer+pTempSectionHeader->VirtualAddress),(void*)((DWORD)pFileBuffer+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
      }
      // 返回数据
      *pImageBuffer = pTempImagebuffer;
      pTempImagebuffer = NULL;
      return pOptionHeader->SizeOfImage;
}

//imagebuffer->newbuffer
DWORD CopyImageBufferToNewBuffer(PVOID pImageBuffer,PVOID* pNewBuffer)
{
      // 初始化PE头部结构体
      PIMAGE_DOS_HEADER pDosHeader = NULL;      
      PIMAGE_NT_HEADERS pNTHeader = NULL;      
      PIMAGE_FILE_HEADER pPEHeader = NULL;      
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;

      // 初始化NEW_BUFFER指针(temparay)
      LPVOID pTempNewbuffer = NULL;

      // 判断pImageBuffer是否有效
      if(!pImageBuffer)
      {
                printf("(2pnewbuffer阶段)读取到内存的pimagebuffer无效!\n");
                return 0;
      }
      //判断是不是exe文件
      if(*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
      {
                printf("(2pnewbuffer阶段)不含MZ标志,不是exe文件!\n");
                return 0;
      }
      // 强制结构体类型转换
      pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
      if(*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
      {
                printf("(2pnewbuffer阶段)不是有效的PE标志!\n");      
                return 0;
      }
      // 强制结构体类型转换
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew);
      pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4); // 这里必须强制类型转换
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);

      //获取new_buffer的大小
      int new_buffer_size = pOptionHeader->SizeOfHeaders;
      for(DWORD i = 0;i<pPEHeader->NumberOfSections;i++)
      {
                new_buffer_size += pSectionHeader.SizeOfRawData;// pSectionHeader另一种加法
      }
      // 分配内存(newbuffer)
      pTempNewbuffer = malloc(new_buffer_size);
      if(!pTempNewbuffer)
      {
                printf("(2pnewbuffer阶段)分配Newbuffer失败!\n");
                return 0;
      }
      memset(pTempNewbuffer,0,new_buffer_size);
      // 拷贝头部
      memcpy(pTempNewbuffer,pDosHeader,pOptionHeader->SizeOfHeaders);
      // 循环拷贝节区
      PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
      for(DWORD j = 0;j<pPEHeader->NumberOfSections;j++,pTempSectionHeader++)
      {      //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
                memcpy((PDWORD)((DWORD)pTempNewbuffer+pTempSectionHeader->PointerToRawData),(PDWORD)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),pTempSectionHeader->SizeOfRawData);
      }
      //返回数据
      *pNewBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
      pTempNewbuffer = NULL;
      return new_buffer_size;// 返回计算得到的分配内存的大小
}

//newbuffer->存盘
int newbuffer_write2_exe(PVOID NewFileBuffer,DWORD FileSize, char* FilePath)
{
      FILE* fp1 = fopen(FilePath,"wb");
      if(fp1 != NULL)
      {
                fwrite(NewFileBuffer,FileSize,1,fp1);
      }
      fclose(fp1);
      return 1;
}

int add_section(PVOID* pNewFileBuffer,PVOID pImageBuffer,DWORD FileSize)
{
      // 初始化PE头部结构体
      PIMAGE_DOS_HEADER pDosHeader = NULL;      
      PIMAGE_NT_HEADERS pNTHeader = NULL;      
      PIMAGE_FILE_HEADER pPEHeader = NULL;      
      PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
      PIMAGE_SECTION_HEADER pSectionHeader = NULL;

      // 判断pImageBuffer是否有效
      if(!pImageBuffer)
      {
                printf("读取到内存的pfilebuffer无效!\n");
                return 0;
      }
      //判断是不是exe文件
      if(*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
      {
                printf("不含MZ标志,不是exe文件!\n");
                return 0;
      }
      // 强制结构体类型转换
      pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
      if(*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
      {
                printf("不是有效的PE标志!\n");      
                return 0;
      }
      // 强制结构体类型转换
      pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew);
      pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4); // 这里必须强制类型转换
      pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);
      pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader);
pSectionHeader++;
      // 判断代码区大小够不够
      if(size_shellcode>(pSectionHeader->SizeOfRawData-pSectionHeader->Misc.VirtualSize))
      {
                printf("代码区空间不足!\n");
                free(pImageBuffer);
                return 0;
      }
      printf("pSectionHeader->PointerToRawData:%#xpSectionHeader->Misc.VirtualSize:%#x\n",pSectionHeader->PointerToRawData,pSectionHeader->Misc.VirtualSize);
      printf("pImageBuffer:%#x\n",pImageBuffer);
      // 将代码复制到空白区
      PBYTE code_begin = (PBYTE)((DWORD)pImageBuffer+pSectionHeader->VirtualAddress+pSectionHeader->Misc.VirtualSize);
      printf("pSectionHeader->VirtualAddress:%#X\n",pSectionHeader->VirtualAddress);
      printf("code_begin:%#x\n",code_begin);
      memcpy(code_begin,shellcode,size_shellcode);
      // 修改E8 跳到messagebox
      DWORD callAddr = (messagebox_add-(pOptionHeader->ImageBase+((DWORD)(code_begin+0xD)-(DWORD)pImageBuffer)));//(DWORD)code_begin+0xoD-(DWORD)pImageBuffer是E8下一条指令的地址的相对偏移
      printf("callAddr:%#X\n",callAddr);
      *(PDWORD)(code_begin+0x09) = callAddr; //填充数据
      // 修改E9 跳回程序开始
      DWORD jmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint)-(pOptionHeader->ImageBase+((DWORD)code_begin+size_shellcode-(DWORD)pImageBuffer)));
      *(PDWORD)(code_begin+0x0E) = jmpAddr;
      // 修改OEP
      pOptionHeader->AddressOfEntryPoint = (DWORD)code_begin - (DWORD)pImageBuffer;
      // imagebuffer->newfilebuffer
      int size = CopyImageBufferToNewBuffer(pImageBuffer,pNewFileBuffer);

      if(size = 0 || !pNewFileBuffer)
      {
                printf("imagebuffer->newfilebuffer失败!\n");
                free(pImageBuffer);
                free(pNewFileBuffer);
      }
      // 存盘
      int ret4 = newbuffer_write2_exe(*pNewFileBuffer,FileSize, write_file_path);
      if(!ret4)
      {
                printf("存盘失败!\n");
                return 0;
      }
      return 1;

}

void operate_pe()
{   
      // 初始化操作
      PVOID pFileBuffer = NULL;
      PVOID pNewFileBuffer = NULL;
      PVOID pImageBuffer = NULL;
      DWORD NewFileBufferSize = 0;
      // exe->filebuffer
      int ret1 = ReadPEFile(file_path,&pFileBuffer);// &pFileBuffer(void**类型) 传递地址对其值可以进行修改
      printf("exe->filebuffer返回值为计算所得文件大小:%#x\n",ret1);

      // filebuffer -> imagebuffer
      int ret2 = CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
      printf("filebuffer -> imagebuffer返回值为计算所得文件大小:%#x\n",ret2);
      
      // add_section
      int ret3 = add_section(&pNewFileBuffer,pImageBuffer,ret1);
      printf("%d",ret3);

      free(pFileBuffer);
      free(pNewFileBuffer);
      free(pImageBuffer);
}

int main()
{      
      operate_pe();
      return 0;
}

但第229行我改成+=2程序可以运行也能弹出窗口,但是在uedit里面我找不到6a00在哪里

cube 发表于 2020-7-3 03:21

用"数据与其所在对应段的偏移地址"在uedit中找.
页: [1]
查看完整版本: 为什么这个程序向notepad第二个节后面加入shellcode代码会失败