用程序在代码节空白处加代码

1.工具头文件
#ifndef PETOOL_H
#define PETOOL_H
 
#include "stdafx.h"
#include <stdlib.h>
#include <windows.h>
 
//函数声明                                
//**************************************************************************                                
//ReadPEFile:将文件读取到缓冲区                                
//参数说明:                                
//lpszFile 文件路径                                
//pFileBuffer 缓冲区指针                                
//返回值说明:                                
//读取失败返回0  否则返回实际读取的大小                                
//**************************************************************************                                
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer);                                
//**************************************************************************                                
//CopyFileBufferToImageBuffer:将文件从FileBuffer复制到ImageBuffer                                
//参数说明:                                
//pFileBuffer  FileBuffer指针                                
//pImageBuffer ImageBuffer指针                                
//返回值说明:                                
//读取失败返回0  否则返回复制的大小                                
//**************************************************************************                                
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer);                                
//**************************************************************************                                
//CopyImageBufferToNewBuffer:将ImageBuffer中的数据复制到新的缓冲区                                
//参数说明:                                
//pImageBuffer ImageBuffer指针                                
//pNewBuffer NewBuffer指针                                
//返回值说明:                                
//读取失败返回0  否则返回复制的大小                                
//**************************************************************************                                
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer);                                
//**************************************************************************                                
//MemeryTOFile:将内存中的数据复制到文件                                
//参数说明:                                
//pMemBuffer 内存中数据的指针                                
//size 要复制的大小                                
//lpszFile 要存储的文件路径                                
//返回值说明:                                
//读取失败返回0  否则返回复制的大小                                
//**************************************************************************                                
BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile);                                
//**************************************************************************                                
//RvaToFileOffset:将内存偏移转换为文件偏移                                
//参数说明:                                
//pFileBuffer FileBuffer指针                                
//dwRva RVA的值                                
//返回值说明:                                
//返回转换后的FOA的值  如果失败返回0                                
//**************************************************************************                                
DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva);                                
#endif
 
2.工具实现
#include "stdafx.h"
#include "petool.h"
 
//ReadPEFile:将文件读取到缓冲区
DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* pFileBuffer){
    //1.打开文件
    FILE* file = fopen(lpszFile, "rb");
    if(!file){
        printf("打开文件失败\n");
        return 0;
    }
    //2.计算文件大小
    fseek(file, 0, SEEK_END);
    DWORD len = ftell(file);
    fseek(file, 0, SEEK_SET);
    //3.申请内存
    LPVOID buf = malloc(len);
    if(!buf){
        fclose(file);
        printf("申请内存失败\n");
        return 0;
    }
    //4.读取文件到内存
    size_t n = fread(buf, len, 1, file);
    if(!n){
        printf("读取文件失败\n");
        free(buf);
        fclose(file);
        return 0;
    }
    //5.返回
    printf("读取文件到缓冲区成功\n");
    *pFileBuffer = buf;
    buf = NULL;
    fclose(file);
    return len;
    
}
 
//将文件从FileBuffer复制到ImageBuffer
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer){
    //定义pe头结构指针
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos头指针
    PIMAGE_NT_HEADERS ntHeader = NULL;        //nt头指针
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe头指针
    PIMAGE_OPTIONAL_HEADER32 optionHeader = NULL;    //可选pe头指针
    PIMAGE_SECTION_HEADER sectionHeader = NULL;    //节表指针
    if(!pFileBuffer){
        printf("文件加载失败\n");
        return 0;
    }
    //判断是否有mz标记
    if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE){
        printf("不是有效mz标记\n");
        return 0;
    }
    //找到dos头
    dosHeader = (PIMAGE_DOS_HEADER) pFileBuffer;
    //根据dos头的e_flanew找到nt头并判断是否有pe标记
    if(*((PDWORD)((DWORD)pFileBuffer + dosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
        printf("不是有效pe标记\n");
        return 0;
    }
    //找到pe头
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)pFileBuffer + dosHeader->e_lfanew +4);
    //找到可选pe头
    optionHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    //**********开始复制***********
    //1.申请内存空间,拉伸后的大小在可选pe头的SizeOfImage中
    DWORD imageSize = optionHeader ->SizeOfImage;
    LPVOID image = malloc(imageSize);
    if(!image){
        printf("申请imagebuf内存空间失败\n");
        return 0;
    }
    //初始化内存空间
    memset(image, 0, imageSize);
    //2.拷贝头部文件,内存镜像和文件镜像的头部是一样的
    DWORD headSize = optionHeader->SizeOfHeaders;
    memcpy(image, pFileBuffer, headSize);
    //3.拷贝各个节
    WORD sectionNum = peHeader->NumberOfSections;    //节的数量在pe头中
    WORD opHeaderSize = peHeader->SizeOfOptionalHeader;    //可选pe头的字节数,用来计算节表文件镜像的位置;
    //找到节表开头
    sectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)optionHeader + opHeaderSize);
    for(int i=0; i<sectionNum; i++,sectionHeader++){
        memcpy((LPVOID)((DWORD)image + sectionHeader->VirtualAddress),
            (LPVOID)((DWORD)pFileBuffer + sectionHeader->PointerToRawData),
            sectionHeader->SizeOfRawData);
    }
    //4.返回
    *pImageBuffer = image;
    printf("拉伸文件镜像成功\n");
    return imageSize;
}
 
//将ImageBuffer中的数据复制到新的缓冲区                                                                                            
DWORD CopyImageBufferToNewBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pNewBuffer){
    //定义pe头结构指针
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos头指针
    PIMAGE_NT_HEADERS ntHeader = NULL;        //nt头指针
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe头指针
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可选pe头指针
    PIMAGE_SECTION_HEADER sectionHeader = NULL;    //节表指针
    //找到dos头
    dosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    //找到nt头
    ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)pImageBuffer + dosHeader->e_lfanew);
    //找到pe头
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)ntHeader + 4);
    //找到可选pe头
    opHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    //找到节表
    sectionHeader = (PIMAGE_SECTION_HEADER) ((DWORD)opHeader + peHeader->SizeOfOptionalHeader);
    //1.申请内存
    //内存镜像压缩后的空间大小:最后一个节的偏移PointerToRawData + 最后一个节的大小SizeOfRawData
    //获取最后一个节的指针
    PIMAGE_SECTION_HEADER pLastSection = sectionHeader + (peHeader->NumberOfSections - 1);
    DWORD size = pLastSection->PointerToRawData + pLastSection->SizeOfRawData;
    //申请内存空间
    LPVOID buf = malloc(size);
    if(!buf){
        printf("压缩内存镜像时:分配空间失败\n");
        return NULL;
    }
    //初始化内存空间
    memset(buf, 0, size);
    //2.拷贝头部文件
    memcpy(buf, pImageBuffer, opHeader->SizeOfHeaders);
    //3.拷贝节
    for(int i=0;i<peHeader->NumberOfSections;i++,sectionHeader++){
        memcpy((LPVOID)((DWORD)buf + sectionHeader->PointerToRawData),
            (LPVOID)((DWORD)pImageBuffer + sectionHeader->VirtualAddress),
            sectionHeader->SizeOfRawData);
    }
    //4.返回
    *pNewBuffer = buf;
    printf("压缩内存镜像成功\n");
    return size;
        
}
 
//MemeryTOFile:将内存中的数据复制到文件                                                                
BOOL MemeryTOFile(IN LPVOID pMemBuffer,IN size_t size,OUT LPSTR lpszFile){
    //打开文件
    FILE* file = fopen(lpszFile, "a+b");
    if(!file){
        printf("打开文件失败\n");
        return 0;
    }
 
    //写出
    size_t n = fwrite(pMemBuffer, size, 1, file);
    if(!n){
        printf("写出文件失败\n");
        fclose(file);
        return 0;
    }
 
    fclose(file);
    return 1;
}    
 
//将内存偏移转换为文件偏移                                                                
DWORD RvaToFileOffset(IN LPVOID pFileBuffer,IN DWORD dwRva){
    //定义文件头
    PIMAGE_DOS_HEADER dosHeader = NULL;        //dos头指针
    PIMAGE_NT_HEADERS ntHeader = NULL;        //nt头指针
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe头指针
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可选pe头指针
    PIMAGE_SECTION_HEADER sectionHeader = NULL;    //节表指针
 
    //找到文件头
    dosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    ntHeader = (PIMAGE_NT_HEADERS) ((DWORD)pFileBuffer + dosHeader->e_lfanew);
    peHeader = (PIMAGE_FILE_HEADER) ((DWORD)ntHeader + 4);
    opHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    sectionHeader = (PIMAGE_SECTION_HEADER) ((DWORD)opHeader + peHeader->SizeOfOptionalHeader);
 
    //1.判断是哪个节
    int sec = -1;
    for(int i=0;i<peHeader->NumberOfSections;i++){
        DWORD va = (sectionHeader+i)->VirtualAddress;
        DWORD size = (sectionHeader+i)->SizeOfRawData;
        if(dwRva > va && dwRva<(va+size) ){
            sec = i;
            printf("在第%d个节\n",sec);
            break;
        }    
    }
    if(sec<0){
        printf("内存偏移不在任何一个节\n");
        return 0;
    }
 
    //2.转换
    DWORD secOffset = dwRva - (sectionHeader + sec)->VirtualAddress;
    DWORD foa = (sectionHeader + sec)->PointerToRawData + secOffset;
 
    return foa;
}
 
3.在空白区添加代码
#include "stdafx.h"
#include "petool.h"
 
#define SHELLCODELEN 18
#define SRC "C:\\Users\\Administrator\\Desktop\\TraceMe.exe"
#define DEST "C:\\Users\\Administrator\\Desktop\\copy1.exe"
#define MESSAGEBOXADDR 0x75780026
 
//需要添加的代码,跳转地址为0
BYTE shellCode[SHELLCODELEN]={
    0x6a,00,0x6a,00,0x6a,00,0x6a,00,
    0xe8,00,00,00,00,
    0xe9,00,00,00,00
};
 
//在代码节空白区添加代码
void addCodeInCodeSec(){
    LPVOID pFileBuffer = NULL;
    LPVOID pImageBuffer = NULL;
    LPVOID pNewBuffer = NULL;
 
    PIMAGE_FILE_HEADER peHeader = NULL;        //pe头指针
    PIMAGE_OPTIONAL_HEADER32 opHeader = NULL;    //可选pe头指针
    PIMAGE_SECTION_HEADER seHeader = NULL;    //节表指针
 
    PBYTE codeBegin = NULL;    //添加代码的起始位置
    DWORD size = 0;        //内存镜像压缩后的大小
    BOOL isOK = FALSE;
 
    //1.从文件中读到缓冲区
    ReadPEFile(SRC, &pFileBuffer);
    if(!pFileBuffer){
        printf("读取文件失败\n");
        return;
    }
    //2.拉伸文件
    CopyFileBufferToImageBuffer(pFileBuffer,&pImageBuffer);
    if(!pImageBuffer){
        printf("拉伸文件失败\n");
        free(pFileBuffer);
        return;
    }
    //3.判断空间是否足够
    peHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageBuffer + ((PIMAGE_DOS_HEADER)pImageBuffer)->e_lfanew + 4);
    opHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)peHeader + IMAGE_SIZEOF_FILE_HEADER);
    seHeader = (PIMAGE_SECTION_HEADER)((DWORD)opHeader + peHeader->SizeOfOptionalHeader);
    //条件是:节的文件对齐大小 - 节的实际大小 > 代码大小
    if(seHeader->SizeOfRawData - seHeader->Misc.VirtualSize < SHELLCODELEN){
        printf("代码节空白区空间不足\n");
        //注意释放申请的内存空间,谁拿到指针谁释放
        free(pFileBuffer);
        free(pImageBuffer);
        return;
    }
    //4.往内存镜像中添加代码
    codeBegin = (PBYTE)((DWORD)(pImageBuffer) + seHeader->VirtualAddress + seHeader->Misc.VirtualSize);
    memcpy(codeBegin, shellCode,SHELLCODELEN);
    //修正e8
    DWORD callAddr = MESSAGEBOXADDR - (opHeader->ImageBase + ((DWORD)codeBegin+0x0d - (DWORD)pImageBuffer));
    *(PDWORD)(codeBegin+9) = callAddr;
    //修正e9
    DWORD jmpAddr = opHeader->AddressOfEntryPoint - ((DWORD)(codeBegin+0x12) - (DWORD)pImageBuffer);
    *(PDWORD)(codeBegin+0x0e) = jmpAddr;
    //修正入口点oep
    opHeader->AddressOfEntryPoint = (DWORD)codeBegin-(DWORD)pImageBuffer;
    //5.压缩内存镜像
    size = CopyImageBufferToNewBuffer(pImageBuffer, &pNewBuffer);
    if(size == 0 || !pNewBuffer){
        printf("压缩内存镜像失败\n");
        free(pFileBuffer);
        free(pImageBuffer);
        return;
    }
    //6.复制压缩后的内存镜像到文件
    isOK = MemeryTOFile(pNewBuffer,size,DEST);
    if(isOK){
        printf("存盘成功\n");
    }else{
        printf("存盘失败\n");
    }
    //7.释放内存
    free(pFileBuffer);
    free(pImageBuffer);
    free(pNewBuffer);
}
 
int main(int argc, char* argv[])
{
    addCodeInCodeSec();
    getchar();
    return 0;
}
 
 
运行结果:
复制了一个文件,运行时加了一个弹框:
 
 
 
posted @ 2019-10-23 16:13  L丶银甲闪闪  阅读(803)  评论(0编辑  收藏  举报