PE文件入门(一)

Shellcode直接注入代码块

使用代码,在文件中将shellcode注入进程序的text节中,也就是代码块中

条件:代码块有足够的空间存下shellcode

思路:获取shellcode的注入位置,然后再通过计算把硬编码应该跳转的地址计算出来  其公式为:要跳转的地址=当前指令的下一条指令地址+5+X——>就可以推出X=要跳转的地址-(当前指令的下一条指令地址+5)

在通过指针将其值修改

在最后修改OEP,并使shellcode最后跳回原来的程序入口

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>


#define SHELLCODELENGTH        0x12
BYTE shellCode[] =
{
    0x6a,00,0x6a,00,0x6a,00,0x6a,00,
    0xe8,00,00,00,00,
    0xe9,00,00,00,00
};

PVOID FileToFileBuffer(LPSTR lpszFile)
{
    FILE* file=NULL;
    PVOID FileBuffer=NULL;
    size_t FileOfSize=0;

    file = fopen(lpszFile, "rb+");
    if (!file)
    {
        printf("文件打开错误");
        return NULL;
    }

    fseek(file, NULL,SEEK_END);
    FileOfSize=ftell(file);
    fseek(file, NULL, SEEK_SET);

    FileBuffer = malloc(FileOfSize);
    if (!FileBuffer)
    {
        printf("内存分配错误");
        fclose(file);
        return NULL;
    }

    if (!fread(FileBuffer, FileOfSize, 1, file))
    {
        printf("文件读取错误");
        fclose(file);
        return NULL;
    }
    fclose(file);
    return FileBuffer;
}

PVOID FileBufferToMemBuffer(LPVOID FileBuffer)
{
    PVOID MemBuffer = NULL;
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;

    pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader+ pFilePEHeader->SizeOfOptionalHeader);
    size_t size = pFileOptionHeader->SizeOfImage;

    MemBuffer = malloc(size);
    memset(MemBuffer, 0, size);
    memcpy(MemBuffer, pFileDosHeader, pFileOptionHeader->SizeOfHeaders);
    

    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize);
        pFileSectionHeader++;
    }
    return MemBuffer;
}

PVOID MemBufferToFile(LPVOID MemBuffer)
{
    FILE* file=NULL;
    PVOID FileBuffer = NULL;
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;
    file = fopen("cpyj.exe", "wb+");

    pFileDosHeader = (PIMAGE_DOS_HEADER)MemBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    size_t size = pFileOptionHeader->SizeOfHeaders;
    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        size += pFileSectionHeader->SizeOfRawData;
        pFileSectionHeader++;
    }
    pFileSectionHeader= (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    
    FileBuffer = malloc(size);
    memset(FileBuffer, 0, size);
    memcpy(FileBuffer, MemBuffer, pFileOptionHeader->SizeOfHeaders);
    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        memcpy((PVOID)((DWORD)FileBuffer+pFileSectionHeader->PointerToRawData), (PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), pFileSectionHeader->SizeOfRawData);
        pFileSectionHeader++;
    }
    fwrite(FileBuffer, size, 1, file);
    return FileBuffer;
}

PVOID TestAddCodeInCodeSec(LPVOID ImageBuffer)
{
    HMODULE AddressOfDll = GetModuleHandle((LPCWSTR)"user32.dll");//这里本机代码我没有求出来,所以messagebox传出来的值为NULL,所以什么都没变
    FARPROC AddressOfMessage = GetProcAddress(AddressOfDll, (LPCSTR)"MessageBox");
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;

    pFileDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    if (((pFileSectionHeader->SizeOfRawData) - (pFileSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
    {
        printf("代码区空间不够");
        return NULL;
    }

    PVOID codeBegin = (PBYTE)((pFileOptionHeader->SizeOfHeaders) + (DWORD)ImageBuffer + pFileSectionHeader->Misc.VirtualSize);
    memcpy(codeBegin, shellCode, SHELLCODELENGTH);

    //修正E8
    DWORD callAddr = ((DWORD)AddressOfMessage - (pFileOptionHeader->ImageBase + (DWORD)codeBegin + 0xD) + (DWORD)ImageBuffer);
    *(PDWORD)((DWORD)codeBegin + 9) = callAddr;
    //修正E9
    DWORD jmpAddr = (pFileOptionHeader->AddressOfEntryPoint+pFileOptionHeader->ImageBase-(pFileOptionHeader->ImageBase + SHELLCODELENGTH) + (DWORD)ImageBuffer);
    *(PDWORD)((DWORD)codeBegin + 0xE) = jmpAddr;
    //修改OEP
    pFileOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)ImageBuffer;

    MemBufferToFile(ImageBuffer);
}

VOID TestAddSection()
{

}

int main()
{
    
    LPSTR lpszFile = (LPSTR)"pe.exe";
    PVOID FileBuffer = FileToFileBuffer(lpszFile);
    PVOID MemBuffer=FileBufferToMemBuffer(FileBuffer);
    TestAddCodeInCodeSec(MemBuffer);
}

上面条件不成立的话,可以通过扩展节来进行注入和跳转,请看下面

通过扩展节来向程序注入shellcode

使用代码,在文件中先增加一个节在,将shellcode注入进我们自己创建的节中

条件:当代码节不够空闲块时,就用此方法(还有一种情况,当不够空闲块的时候,由于DOS头下面有一部分没有用的垃圾数据,所以可以把PE整个头上移,并修改DOS头的flnew成员,其他的修改一致)

思路:在程序最后一个节后面添加字节,因为如果添加到前面,需要改变节表里的多个值,然后在修改节表里的值,也就是在节表后面新增一个SectionHeader,Name8个字节随便设,并用character与text节处的character进行或运算,在修改文件大小和内存大小为相等(这样可以省去一些写入步骤)和偏移地址,在设置标准头里的SizeOfSections,在设置SizeOfImage, 获取shellcode的注入位置,然后再通过计算把硬编码应该跳转的地址计算出来  其公式为:要跳转的地址=当前指令的下一条指令地址+5+X——>就可以推出X=要跳转的地址-(当前指令的下一条指令地址+5)

在通过指针将其值修改

在最后修改OEP,并使shellcode最后跳回原来的程序入口

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>


#define SHELLCODELENGTH        0x12
BYTE shellCode[] =
{
    0x6a,00,0x6a,00,0x6a,00,0x6a,00,
    0xe8,00,00,00,00,
    0xe9,00,00,00,00
};

PVOID FileToFileBuffer(LPSTR lpszFile)
{
    FILE* file=NULL;
    PVOID FileBuffer=NULL;
    size_t FileOfSize=0;

    file = fopen(lpszFile, "rb+");
    if (!file)
    {
        printf("文件打开错误");
        return NULL;
    }

    fseek(file, NULL,SEEK_END);
    FileOfSize=ftell(file);
    fseek(file, NULL, SEEK_SET);

    FileBuffer = malloc(FileOfSize);
    if (!FileBuffer)
    {
        printf("内存分配错误");
        fclose(file);
        return NULL;
    }

    if (!fread(FileBuffer, FileOfSize, 1, file))
    {
        printf("文件读取错误");
        fclose(file);
        return NULL;
    }
    fclose(file);
    return FileBuffer;
}

PVOID FileBufferToMemBuffer(LPVOID FileBuffer)
{
    PVOID MemBuffer = NULL;
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;

    pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader+ pFilePEHeader->SizeOfOptionalHeader);
    size_t size = pFileOptionHeader->SizeOfImage;

    MemBuffer = malloc(size);
    memset(MemBuffer, 0, size);
    memcpy(MemBuffer, pFileDosHeader, pFileOptionHeader->SizeOfHeaders);
    

    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize);
        pFileSectionHeader++;
    }
    return MemBuffer;
}

PVOID MemBufferToFile(LPVOID MemBuffer)
{
    FILE* file=NULL;
    PVOID FileBuffer = NULL;
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;
    file = fopen("cpyj.exe", "wb+");

    pFileDosHeader = (PIMAGE_DOS_HEADER)MemBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    size_t size = pFileOptionHeader->SizeOfHeaders;
    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        size += pFileSectionHeader->SizeOfRawData;
        pFileSectionHeader++;
    }
    pFileSectionHeader= (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    
    FileBuffer = malloc(size);
    memset(FileBuffer, 0, size);
    memcpy(FileBuffer, MemBuffer, pFileOptionHeader->SizeOfHeaders);
    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        memcpy((PVOID)((DWORD)FileBuffer+pFileSectionHeader->PointerToRawData), (PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), pFileSectionHeader->SizeOfRawData);
        pFileSectionHeader++;
    }
    fwrite(FileBuffer, size, 1, file);
    return FileBuffer;
}

PVOID TestAddCodeInCodeSec(LPVOID ImageBuffer)
{
    HMODULE AddressOfDll = GetModuleHandle((LPCWSTR)"user32.dll");
    FARPROC AddressOfMessage = GetProcAddress(AddressOfDll, (LPCSTR)"MessageBox");
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;

    pFileDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);
    if (((pFileSectionHeader->SizeOfRawData) - (pFileSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH)
    {
        printf("代码区空间不够");
        return NULL;
    }

    PVOID codeBegin = (PBYTE)((pFileOptionHeader->SizeOfHeaders) + (DWORD)ImageBuffer + pFileSectionHeader->Misc.VirtualSize);
    memcpy(codeBegin, shellCode, SHELLCODELENGTH);

    //修正E8
    DWORD callAddr = ((DWORD)AddressOfMessage - (pFileOptionHeader->ImageBase + ((DWORD)((DWORD)codeBegin + 0xD) - (DWORD)ImageBuffer)));
    *(PDWORD)((DWORD)codeBegin + 9) = callAddr;
    //修正E9
    DWORD jmpAddr = (pFileOptionHeader->AddressOfEntryPoint+pFileOptionHeader->ImageBase-(pFileOptionHeader->ImageBase + SHELLCODELENGTH) + (DWORD)ImageBuffer);
    *(PDWORD)((DWORD)codeBegin + 0xE) = jmpAddr;
    //修改OEP
    pFileOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)ImageBuffer;

    MemBufferToFile(ImageBuffer);
}

VOID TestAddSection(LPSTR path)
{
    PVOID FileBuffer = FileToFileBuffer(path);
    PVOID MemBuffer = NULL;
    PIMAGE_DOS_HEADER pFileDosHeader = NULL;
    PIMAGE_NT_HEADERS pFileNTHeader = NULL;
    PIMAGE_FILE_HEADER pFilePEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pFileSectionHeader = NULL;

    pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
    pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4);
    pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader);

    size_t Addsize=pFileOptionHeader->SectionAlignment;
    
    
    pFileOptionHeader->SizeOfImage += Addsize;
    PIMAGE_SECTION_HEADER AddSectionHeader= pFileSectionHeader + pFilePEHeader->NumberOfSections;

    AddSectionHeader->SizeOfRawData=AddSectionHeader->Misc.VirtualSize = Addsize;
    AddSectionHeader->PointerToRawData = ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->PointerToRawData + ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->SizeOfRawData;
    AddSectionHeader->VirtualAddress = ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->VirtualAddress + (((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->Misc.VirtualSize/pFileOptionHeader->SectionAlignment+1)* pFileOptionHeader->SectionAlignment;
    AddSectionHeader->Characteristics |= pFileSectionHeader->Characteristics;
    AddSectionHeader->Name[0] = '.';
    AddSectionHeader->Name[1] = 't';
    AddSectionHeader->Name[2] = 't';
    AddSectionHeader->Name[3] = 't';
    AddSectionHeader->Name[4] = 't';
    pFilePEHeader->NumberOfSections++;

    MemBuffer = malloc(pFileOptionHeader->SizeOfImage);
    memset(MemBuffer, 0, pFileOptionHeader->SizeOfImage);
    memcpy(MemBuffer, FileBuffer, pFileOptionHeader->SizeOfHeaders);
    for (int i = 0; i < pFilePEHeader->NumberOfSections; i++)
    {
        memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize);
        pFileSectionHeader++;
    }
    MemBufferToFile(MemBuffer);
    return;
}


int main()
{
    
    LPSTR lpszFile = (LPSTR)"pe.exe";
    PVOID FileBuffer = FileToFileBuffer(lpszFile);
    PVOID MemBuffer=FileBufferToMemBuffer(FileBuffer);
    TestAddSection(lpszFile);
}

如果上面两种情况都不适用,那么可以扩大节

通过扩大节来注入shellcode

使用代码扩大最后一个节

条件:暂时不清楚

思路:在最后一个节里加上一段内存,并且修改sizeofimage和sectionheader里的文件大小和内存大小全部修改,建议修改为一样的。即可

代码跟上面这种方法差不多

还有一种方法合并节

顾名思义就是将所有的节合并为一个节

思路:把多个节合并为一个,需要修改的值为:sectionheader,内存大小,和文件大小,NumberOfSections需要修改

需要注意的是文件对齐

代码先咕一下等基本的PE干了,在过来一次添加上

原文地址:https://www.cnblogs.com/pppyyyzzz/p/13262139.html