病毒实验五

title: viruslab5
date: 2016-01-13 15:47:40
categories: virus
tags: virus
---

PE文件注入

  • part1
    • 要求:附带程序将一个完整的PE文件(hellow.exe)读到内存中
      并将其分解为PE头、节表、以及各个节。
      试编写void OutputPEInMem()函数,用其打印下列信息:
      • PE头中的ImageBase字段、AddressOfEntryPoint字段、
        NumberOfSections字段与SizeOfImage字段;
      • 节表(Section Table)中每一项的Name字段、Virtual Size字段、Virtual Address字段、
        RawData Size字段、RawData Offset字段、Characteristics字段。
        ```c

        include <windows.h>

        include <stdio.h>

        define MAX_SECTION_NUM 16

        define MAX_IMPDESC_NUM 64

      HANDLE hHeap;
      DWORD dwBaseAddress;
      PIMAGE_DOS_HEADER pDosHeader;
      PCHAR pDosStub;
      DWORD dwDosStubSize;
      DWORD dwDosStubOffset;
      PIMAGE_NT_HEADERS pNtHeaders;
      PIMAGE_FILE_HEADER pFileHeader;
      PIMAGE_OPTIONAL_HEADER32 pOptHeader;
      PIMAGE_SECTION_HEADER pSecHeaders;
      PIMAGE_SECTION_HEADER pSecHeader[MAX_SECTION_NUM];
      WORD wSecNum;
      PBYTE pSecData[MAX_SECTION_NUM];
      DWORD dwSecSize[MAX_SECTION_NUM];
      DWORD dwFileSize;

      static DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo)
      {
      //PEAlign参数1:源节表 文件中的块大小
      //PEAlign参数2:文件对齐值
      //返回对齐后的文件大小
      return (((dwTarNum+dwAlignTo - 1) / dwAlignTo) * dwAlignTo);
      }

      static DWORD RVA2Ptr(DWORD dwBaseAddress, DWORD dwRva)
      {
      if ((dwBaseAddress != 0) && dwRva)
      return (dwBaseAddress + dwRva);
      else
      return dwRva;
      }

      //----------------------------------------------------------------
      static PIMAGE_SECTION_HEADER RVA2Section(DWORD dwRVA)
      {
      int i;
      for(i = 0; i < wSecNum; i++) {
      if ( (dwRVA >= pSecHeader[i]->VirtualAddress)
      && (dwRVA <= (pSecHeader[i]->VirtualAddress
      + pSecHeader[i]->SizeOfRawData)) ) {
      return ((PIMAGE_SECTION_HEADER)pSecHeader[i]);
      }
      }
      return NULL;
      }

      //----------------------------------------------------------------
      static PIMAGE_SECTION_HEADER Offset2Section(DWORD dwOffset)
      {
      int i;
      for(i = 0; i < wSecNum; i++) {
      if( (dwOffset>=pSecHeader[i]->PointerToRawData)
      && (dwOffset<(pSecHeader[i]->PointerToRawData +
      pSecHeader[i]->SizeOfRawData)))
      {
      return ((PIMAGE_SECTION_HEADER)pSecHeader[i]);
      }
      }
      return NULL;
      }

      //================================================================
      static DWORD RVA2Offset(DWORD dwRVA)
      {
      PIMAGE_SECTION_HEADER pSec;
      pSec = RVA2Section(dwRVA);//ImageRvaToSection(pimage_nt_headers,Base,dwRVA);
      if(pSec == NULL) {
      return 0;
      }
      return (dwRVA + (pSec->PointerToRawData) - (pSec->VirtualAddress));
      }
      //----------------------------------------------------------------
      static DWORD Offset2RVA(DWORD dwOffset)
      {
      PIMAGE_SECTION_HEADER pSec;
      pSec = Offset2Section(dwOffset);
      if(pSec == NULL) {
      return (0);
      }
      return(dwOffset + (pSec->VirtualAddress) - (pSec->PointerToRawData));
      }
      //将PE结构复制到内存的堆中
      BOOL CopyPEFileToMem(LPCSTR lpszFilename)
      {
      HANDLE hFile;
      PBYTE pMem;
      DWORD dwBytesRead;
      int i;
      DWORD dwSecOff;

      PIMAGE_NT_HEADERS pMemNtHeaders;
      PIMAGE_SECTION_HEADER pMemSecHeaders;

      hFile = CreateFile(//返回文件句柄
      lpszFilename,//文件名 这里是hello.exe可执行文件
      GENERIC_READ,//访问模式 读
      FILE_SHARE_READ,//共享模式
      NULL,//指向安全属性的指针
      OPEN_EXISTING,//如何创建
      FILE_ATTRIBUTE_NORMAL,//文件属性
      0);//用于复制文件句柄

      if (hFile == INVALID_HANDLE_VALUE) {//INVALID_HANDLE_VALUE 表示出错
      printf("[E]: Open file (%s) failed.\n", lpszFilename);
      return FALSE;
      }
      dwFileSize = GetFileSize(hFile, 0);//判断文件长度 返回文件大小
      printf("[I]: Open file (%s) ok,
      with size of 0x%08x.\n", lpszFilename, dwFileSize);

      //pMem是hello.exe在堆中的首地址 也就是dos头地址
      pMem = (PBYTE)HeapAlloc(//在堆上分配内存 返回指向所分配内存块的首地址的指针
      hHeap,//main函数中有 是全局变量 要分配堆的句柄
      HEAP_ZERO_MEMORY,//将分配的内存全部清零
      dwFileSize);//要分配堆的字节数

      if(pMem == NULL) {//在堆上分配内存失败
      printf("[E]: HeapAlloc failed (with the size of 0x%08x).\n", dwFileSize);
      CloseHandle(hFile);
      return FALSE;
      }

      ReadFile(//从文件指针指向的位置开始将数据读到一个文件中
      hFile,//文件句柄
      pMem,//用于保存读入数据的一个缓冲区 这里是堆中分配的内存首地址
      dwFileSize,//要读入的字节数
      &dwBytesRead,//指向实际读取字节数的指针
      NULL);
      CloseHandle(hFile);//关闭内核对象

      //复制dos header
      //堆中的dos头pDosHeader
      //在堆上分配内存 返回指向所分配内存块的首地址的指针
      pDosHeader = (PIMAGE_DOS_HEADER)HeapAlloc(
      hHeap,//main函数中有 是全局变量 要分配堆的句柄
      HEAP_ZERO_MEMORY,//将分配的内存全部清零
      sizeof(IMAGE_DOS_HEADER));//要分配堆的字节数
      if(pDosHeader == NULL) {//在堆上分配内存失败
      printf("[E]: HeapAlloc failed for DOS_HEADER\n");
      CloseHandle(hFile);
      return FALSE;
      }
      CopyMemory(//将内存中的数据从一个位置复制到另一个位置
      pDosHeader,//要复制内存块的目的地址
      pMem,//要复制内存块的源地址
      sizeof(IMAGE_DOS_HEADER));//要复制内存块的大小

      //复制DOS Stub
      //先计算dos stub的大小 dos头大小
      //然后分配dos stub大小的内存空间
      dwDosStubSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER);
      dwDosStubOffset = sizeof(IMAGE_DOS_HEADER);
      pDosStub = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwDosStubSize);
      if ((dwDosStubSize & 0x80000000) == 0x00000000)//dwDosStubSize 最高位是0
      {
      CopyMemory(pDosStub,
      (const void *)(pMem + dwDosStubOffset ), dwDosStubSize);
      }

      //复制NT header
      //先找到源堆中的NT头地址 pMemNtHeaders
      //分配NT头内存空间 返回目的NT头地址 pNtHeaders
      //复制
      pMemNtHeaders = (PIMAGE_NT_HEADERS)(pMem + pDosHeader->e_lfanew);
      //返回目的NT头地址
      pNtHeaders = (PIMAGE_NT_HEADERS)
      HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(IMAGE_NT_HEADERS));
      if(pNtHeaders == NULL) {
      printf("[E]: HeapAlloc failed for NT_HEADERS\n");
      CloseHandle(hFile);
      return FALSE;
      }
      //pMemNtHeaders 源地址
      CopyMemory(pNtHeaders, pMemNtHeaders, sizeof(IMAGE_NT_HEADERS));

      //NT头里面有一个OPT头 目的 pOptHeader
      pOptHeader = &(pNtHeaders->OptionalHeader);
      //NT头里面有一个FILE头 目的 pFileHeader
      pFileHeader = &(pNtHeaders->FileHeader);

      //复制 节表
      //寻找源节表地址 pMemSecHeaders源
      //通过NT头找到FIFE头 FIFE头中有节的数目 wSecNum
      //分配节表的内存空间 返回节表地址 pSecHeaders 目的
      //复制
      pMemSecHeaders = (PIMAGE_SECTION_HEADER) ((DWORD)
      pMemNtHeaders + sizeof(IMAGE_NT_HEADERS));
      wSecNum = pFileHeader->NumberOfSections;//文件节的数目
      pSecHeaders = (PIMAGE_SECTION_HEADER)
      HeapAlloc(hHeap,
      HEAP_ZERO_MEMORY, wSecNum * sizeof(IMAGE_SECTION_HEADER));
      if(pSecHeaders == NULL) {
      printf("[E]: HeapAlloc failed for SEC_HEADERS\n");
      CloseHandle(hFile);
      return FALSE;
      }//pMemSecHeaders 源
      CopyMemory(pSecHeaders,
      pMemSecHeaders, wSecNum * sizeof(IMAGE_SECTION_HEADER));

      for(i = 0; i < wSecNum; i++) {//pSecHeaders 目的
      pSecHeader[i] = (PIMAGE_SECTION_HEADER) //pSecHeader[i] 各个节表 目的
      ((DWORD)pSecHeaders + i * sizeof(IMAGE_SECTION_HEADER));
      }

      //复制节
      //(目的节表 文件中的块偏移 + dos头地址 ) 复制到 dwSecOff
      //PEAlign()返回对齐后的文件大小 dwSecSize
      //分配堆中内存 返回内存首地址 pSecData
      //复制
      for(i = 0; i < wSecNum; i++) {//PointerToRawData 源节表 文件中节偏移
      dwSecOff = (DWORD)(pMem + pSecHeader[i]->PointerToRawData);
      //PEAlign参数1:源节表 文件中的块大小
      //PEAlign参数2:文件对齐值
      dwSecSize[i] = PEAlign(pSecHeader[i]->SizeOfRawData,
      pOptHeader->FileAlignment);
      pSecData[i] = (PBYTE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, dwSecSize[i]);
      if (pSecData[i] == NULL) {
      printf("[E]: HeapAlloc failed for the section of %d\n", i);
      CloseHandle(hFile);
      return FALSE;
      }
      CopyMemory(pSecData[i], (PVOID)dwSecOff, dwSecSize[i]);
      }

      HeapFree(//释放堆内存
      hHeap,//堆句柄
      0,
      pMem);//被释放的内存块首地址 pMem 源
      printf("[I]: Load PE from file (%s) ok\n", lpszFilename);

      return TRUE;
      }

      void OutputPEInMem()
      {
      int i;
      printf("**********************\n");
      printf("Base Address: 0x%08x\n", pDosHeader);
      printf("e_lfanew: 0x%08x\n", pDosHeader->e_lfanew);
      printf("PE NT Headers Address: 0x%08x\n", pNtHeaders);
      printf("NumberOfSections: 0x%08x\n",wSecNum);
      //AddressOfEntryPoint 程序入口RVA地址
      printf("AddressOfEntryPoint: 0x%08x\n", pOptHeader->AddressOfEntryPoint);
      //ImageBase 基址
      printf("ImageBase: 0x%08x\n", pOptHeader->ImageBase);
      //SizeOfImage 映像大小
      printf("SizeOfImage: 0x%08x\n", pOptHeader->SizeOfImage);
      printf("-------------------\n");
      for(i = 0;i < wSecNum;i++)
      {//pSecHeader 目的节表
      printf("pSecHeaders:%s\n",pSecHeader[i]->Name);
      printf("VirtualSize:0x%08x\n",
      pSecHeader[i]->Misc.VirtualSize);//内存中节大小
      printf("VirtualAddress:0x%08x\n",
      pSecHeader[i]->VirtualAddress);//内存中节RVA值
      printf("SizeOfRawData:0x%08x\n",
      pSecHeader[i]->SizeOfRawData);//文件中的节大小
      printf("PointerToRawData:0x%08x\n",
      pSecHeader[i]->PointerToRawData);//文件中的节偏移
      printf("Characteristics:0x%08x\n",
      pSecHeader[i]->Characteristics);//节属性
      printf("-------------------\n");
      }
      return;
      }

      int main()
      {
      LPCSTR lpszFileName = "hello.exe";
      //L:long指针 P:指针 C:常量 STR:字符串
      LPCSTR lpszInjFileName = "hello_inj0.exe";
      hHeap = GetProcessHeap();
      //GetProcessHeap返回调用进程的默认内存堆句柄
      if (! CopyPEFileToMem(lpszFileName)) {//复制PE结构进入堆
      return 1;
      }
      OutputPEInMem();//打印堆中的PE结构
      return 0;
      }

```


  • part2
  • 为”hello.exe”PE结构增加一个新的节,填入4个0xCC的值。具体步骤为:
    • 为PE结构添加一个新的节。
      请仔细阅读所附的AddNewSection()函数的代码,并理解如何为PE结构添加一个可执行的新节。
      请填充函数中的所缺失的两处代码。请理解并使用PEAlign函数来完成对齐操作。
    • 请编写函数SaveMemToPEFile()来将修改过的PE结构重新打包保存为可执行文件”hello_inj0.exe”。
      该函数的原型声明如下:
      BOOL SaveMemToPEFile(LPCSTR lpszFileName)
      请确保新文件”hello_inj0.exe”的正确性,并可以正常运行。
      然后请用Ollydbg来确认新节已正确插入到PE结构中。

转载于:https://www.cnblogs.com/ailx10/p/5251629.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值