用程序在代碼節空白處加代碼


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;
}
 
 
運行結果:
復制了一個文件,運行時加了一個彈框:
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM