zoukankan      html  css  js  c++  java
  • 病毒实验五

    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字段。
    	#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.
    ", lpszFilename);
    	return FALSE;
    	}
    	dwFileSize = GetFileSize(hFile, 0);//判断文件长度 返回文件大小
    	printf("[I]: Open file (%s) ok, 
    	with size of 0x%08x.
    ", 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).
    ", 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
    ");
    	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
    ");
    	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
    ");
    	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
    ", 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
    ", lpszFilename);
    
    	return TRUE;
    	}
    
    	void OutputPEInMem()
    	{
    	int i;
    	printf("**********************
    ");
    	printf("Base Address: 0x%08x
    ", pDosHeader);    
    	printf("e_lfanew: 0x%08x
    ", pDosHeader->e_lfanew);    
    	printf("PE NT Headers Address: 0x%08x
    ", pNtHeaders);
    	printf("NumberOfSections: 0x%08x
    ",wSecNum);
    	//AddressOfEntryPoint 程序入口RVA地址
    	printf("AddressOfEntryPoint: 0x%08x
    ", pOptHeader->AddressOfEntryPoint);
    	//ImageBase 基址
    	printf("ImageBase: 0x%08x
    ", pOptHeader->ImageBase);
    	//SizeOfImage 映像大小
    	printf("SizeOfImage: 0x%08x
    ", pOptHeader->SizeOfImage);
    	printf("-------------------
    ");
    	for(i = 0;i < wSecNum;i++)
    	{//pSecHeader 目的节表
    	printf("pSecHeaders:%s
    ",pSecHeader[i]->Name);
    	printf("VirtualSize:0x%08x
    ",
    	pSecHeader[i]->Misc.VirtualSize);//内存中节大小
    	printf("VirtualAddress:0x%08x
    ",
    	pSecHeader[i]->VirtualAddress);//内存中节RVA值
    	printf("SizeOfRawData:0x%08x
    ",
    	pSecHeader[i]->SizeOfRawData);//文件中的节大小
    	printf("PointerToRawData:0x%08x
    ",
    	pSecHeader[i]->PointerToRawData);//文件中的节偏移
    	printf("Characteristics:0x%08x
    ",
    	pSecHeader[i]->Characteristics);//节属性
    	printf("-------------------
    ");
    	}
    	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结构中。
    ========================if i have some wrong, please give me a message, thx.========================
  • 相关阅读:
    腾讯云CDN python SDK
    GLFW初体验
    Mac使用Xcode配置openGL
    sklearn神经网络分类
    sklearn LDA降维算法
    sklearn CART决策树分类
    sklearn逻辑回归
    抢占式内核与非抢占式内核
    操作系统原理学习笔记--进程管理
    操作系统原理4——存储管理
  • 原文地址:https://www.cnblogs.com/ailx10/p/5251629.html
Copyright © 2011-2022 走看看