代码节空白区添加代码

一、代码节空白区添加代码

1.MessageBox函数说明

  • MessageBox()函数:功能是弹出一个标准的Windows对话框;它不是C函数库的标准函数,而是一个API,我们可以用C语言调用API函数。可以理解成我们在C中使用MessageBox函数就表示调用系统提供的API函数–MessageBoxA。包含在头文件windows.h;如果一个程序中包含user32.dll,则此程序就有MessageBoxAAPI函数

  • MessageBox它是一个宏,有MessageBoxA和MessageBoxW

    我们要找的是MessageBoxA函数的地址

    bp MessageBoxA

    这条命令的意思是在这个MessageBoxA函数这里 设置一个断点

  • 函数原型:

  • int MessageBox( HWND hWnd,LPCTSTR lpText, LPCTSTR lpCaption = NULL, UINT nType = MB_OK );
    ​

四个参数说明:

  1. hWnd:表示窗口句柄,指定该对话框的所有者窗口;如果该参数为空(0/NULL),则该对话框不属于任何窗口

  2. lpText:字符串,指显示在对话框中的内容

  3. lpCaption:字符串,指对话框的标题;如果此参数为空,则默认使用“错误”作为标题

  4. nType:指定显示按钮的数目及形式,表名使用的图标样式、缺省按钮是什么、以及消息框的强制回应等

2.call与jmp指令的硬编码

  • 由于我们现在还没有系统学习过硬编码知识,所以只能先自己编写C看看:我们任意在VC中写一个函数再调用它,编译进入到反汇编查看,右键打开code bytes显示硬编码,可以看到每条指令的左边都是它对应的硬编码,即二进制数(这里用十六进制显示)

call指令的硬编码:E8 后面跟了4个字节(转换后的地址)

jmp指令的硬编码:E9 后面跟了4个字节(转换后的地址)

push指令的硬编码:6A 参数的值(传入函数参数的值是什么对应的参数硬编码就是什么)

  • 由于call指令和jmp指令后面跟的是我们想要调用的函数地址或者跳转的地址,那E8和E9后面跟的4个字节是不是就是这个地址本身呢?不是!E8和E9后面跟的地址数据是需要转换得到的

E8 和 E9 后面4字节地址X的转换公式:

真正要跳转的地址这条指令的下一行地址

因为call 地址的硬编码固定一共占5字节,所以E8指令的下一行地址 = E8当前地址 + 5;所以公式最终为:X = 要跳转的地址 - (E8的地址 + 5)

注意:这些公式中所用到的地址值全部是可执行文件在4GB内存中的地址值,不是文件地址!

3.添加代码效果说明

  • 我们将一段MessageBox函数添加到一个可执行文件中,当我们双击此文件时先弹出我们写的弹框窗口,点击确定按钮后再重新正常执行文件

  • 所以我们的目的就是将此可执行文件的入口改成我们添加的代码位置,执行完代码后再jmp到此文件的原来的入口地址

  • 注意在代码节空白区添加代码相当于给在硬盘上的文件中添加数据,添加完后再运行文件,所以这个过程可以理解为文件注入;但是我们平时说的注入,则是文件在运行时我把代码添加进去,这个过程可以理解为内存注入

4.添加思路

  • 如何知道运行时MessageBoxAPI函数的地址?

  • 使用OD打开可执行文件,在左下角的命令栏输入:bp MessageBoxA回车,表示在此函数起始位置设置断点,接着我们点击上方栏中的B按钮,表示查看断点,接着双击我们刚设置的断点会跳转到断点所在位置,这个地址就是MessageBoxA函数的起始地址

  • 还要记下来此程序本来的入口地址:通过可选PE头中的AddressOfEntryPoint字段值可以知道程序入口地址的偏移量,再通过可选PE头中的ImageBase字段知道文件装载到内存中的起始地址,根据ImageBase + AddressOfEntryPoint可以得出来程序在4GB内存中的真正的入口地址

  • 按照要求,我们只需要构造这样一个功能的代码:①pushMessageBox函数需要的4个参数;②call MessageBox函数地址;③jmp 程序原来的入口地址。

  • 先初步判断空白区的长度是否能存放得下添加的硬编码(使用节对应的节表中的-SizeOfRawData-Misc.VirtualSize 计算空白区的大小)。因为push4个参数,一个push硬编码长度为2字节;call和jmp硬编码长度为5字节;加起来一共是18字节。

  • 接着将这个功能的代码转换成对应的硬编码:其中需要计算E8 和 E9后面的地址,所以要用公式X = 要跳转的地址 - (E8的地址 + 5)进行计算,如果我们使用UE编辑器打开可执行文件进行编辑修改,由于UE编辑器打开的文件是在硬盘上的状态,即我们如果在UE或者winhex中改数据是改的FileBuffer中的数据,不是ImageBuffer中的,则公式的地址都是需要从文件地址转换成内存地址后再计算的!

如果是ipmsg.exe,由于在文件对齐和内存对齐是一样的,所以文件在硬盘上的数据格式和加载到内存中的格式是一样的,那使用UE打开上面显式的地址是什么就用就行,因为文件地址此时等于内存地址

但是如果是notepad.exe等,文件对齐和内存对齐不一样,从硬盘加载到内存是需要"拉伸"的,所以如果此时用UE添加硬编码计算E8 E9后面的地址值时需要使用内存地址,所以多了一个转化的过程

  • 定位到任意一个节后面的空白区,将这段硬编码加到任意节的空白区中,但是最好是代码节中(节的名字一般默认为.text),因为代码区的属性一般是可执行的,所以加到代码节中不用修改节的characteristic属性。记下来这段添加的硬编码的起始偏移地址

  • 我们如果写程序来模拟这个过程,添加硬编码在"拉伸"后的文件中添加

    • 因为我们添加的硬编码中有call和jmp指令后面的地址,这个地址是要转化能得到的—X = 要跳转的地址 - (E8的地址 + 5),转换完才得到了添加的代码的完整硬编码,而地址转化公式中使用的E8当前的地址 + 5,这个E8当前的地址值为文件运行时装入4GB内存(拉伸后)后的值;而且公式中要跳转的地址也是文件装入内存后的MessageBoxA函数的地址。综上我们应该将要添加的硬编码添加到拉伸后的文件任意节的空白区中,这样更方便计算E8 和 E9后面跟的地址值。如果我们想在文件在硬盘上的状态中添加也可以,但是计算E8 和 E9 后面跟的地址值使用公式前,还要自己先把文件地址转换成内存地址,就比较麻烦

二、作业

1.在代码空白区添加代码(手动)

方法一:在FileBuffer中添加代码

准备步骤

  • 打开复制一份notepad.exe,命名为newpad.exe

  • 使用OD打开newpad.exe,OD会模拟newpad.exe运行时装入内存中的状态,输入bp MessageBoxA,找到MessageBoxA函数的地址0x77D36476

  • 使用winhex打开newpad.exe,现在开始所有的地址还是数据都是FileBuffer中的,即文件在硬盘上时状态的数据

  • 我们先定位到newpad.exe的代码区(一般名为.text):DOS头最后4字节为0xE8,找到0xE8往后数24字节即为PE签名 + 标准PE头,标准PE头的倒数第四个字节取WORD款的数据为0xE0,表示可选PE头的大小为0xE0,那么接着往后数0xE0字节,即可定位到第一个节表开始;找到一个节表看前8字节,ASCII码转换成字符串为.text,表示这个节表中的信息就是描述.text节的,即我们所要找的代码区。再接着找到此节表的PointerToRawData字段值为0x400,表示.text节起始地址为0x400(相对于文件起始地址的偏移地址)

  • 定位到0x400,我们再通过节表的Misc.VirtualSize字段的值为0x6D72,通过0x400 + 0x6D72可以大致确定.text节的没有对齐的自身的结束位置0x7172。再通过下一个节表的PointerToRawData字段值为0x7200,(PointerToRawData+SizeOfRawData也可以判断下一个节的起始位置)综合0x7172可以判断出.text节的空白区大小为0x7200 - 0x7172 = 0x8E。所以我们可以将代码添加在这里

构造ShellCode:

1.我们就添加一个最简单的弹框,即MessageBox(0,0,0,0)。汇编代码为:

push 00
push 00
push 00
push 00
call 程序运行时的MessageBoxA的地址(即ImageBuffer中的地址)

我们知道当执行完MessageBox函数最后还要重新让程序运行,所以还要加一个汇编指令:

jmp 程序原来的程序入口地址(AddressOfEntryPoint)

我们要将这些指令转化成对应的硬编码:

push 00:硬编码为6A 00
call:硬编码为E8,后面跟的MessageBoxA地址需要转化,但是长度是确定的5字节
jmp:硬编码为E9,后面跟的原来的程序入口地址也需要转化,但是长度也是确定的5字节

所以先初步估算一下:这段要添加的代码对应的硬编码长度为18字节,明显小于.text空白区的长度0x8E,所以可以添加到代码区的空白区处

2.计算E8 和 E9 后面的地址值:

  • 我们先把已经确定的shellcode在代码区的空白区写好,6A 00 6A 00 6A 00 6A 00传入MessageBoxA函数的四个参数0的硬编码是确定的,所以写好;后面call的硬编码是E8确定的,但是后面四字节的call地址还不确定,先把位置空出来;然后jmp的硬编码也是确定的E9,同样后面的4字节地址还没算出来,所以先空下来。

  • 接着为了将地址补全,需要用公式X = 要跳转的地址 - (E8当前的内存地址 + 5),由于现在加的位置是文件在硬盘上的地址,不是加载到ImageBuffer中的地址,所以要做地址转换:E8文件地址为0x717A,相对于代码区.text开始地址的偏移量为0x717A - 0x400 = 0x6D7A;再找.text节在内存中的起始地址(ImageBase + VirtualAddress)0x1000000 + 0x1000 = 0x1001000;接着用0x1001000 + 0x6D7A = 0x1007D7A就得到了E8的内存地址;因为开始已经确认过MessageBoxA函数的内存中地址为0x77D36476,所以X = 0x77D36476 - (0x1007D7A + 5) = 0x76D2E6F7

  • 算出了上面,就可以得到E9的内存地址为0x1007D7A + 5 = 0x1007D7F,由于原来的OEP的值为0x6AE0,这是偏移量,加上ImageBase后才是内存地址,所以0x1000000 + 0x6AE0 = 0x1006AE0,所以E9后面的值X = 0x1006AE0 - (0x1007D7F + 5) = 0xFFFFED5C

现在完整的shellcode硬编码为:6A 00 6A 00 6A 00 6A 00 E8 F7 E6 D2 76 E9 5C ED FF FF

  • 最后我们手动的把程序的AddressOfEntryPoint字段的值改为这段shellcode硬编码在ImageBuffer的偏移起始地址0x7D72

  • 我们如果还想验证一下我们加的那段代码在程序运行时,即装入ImageBuffer时在什么位置,我们双击运行一下newpad.exe,接着打开winhex–Tools–open ram–找到newpad–展开后找到newpad.exe双击,接着此时的数据就是此时正在运行时的newpad.exe的数据,那么我们找到.text节的空白区,可以发现此时我们添加的代码就在这里:

方法二:在ImageBuffer中添加代码

和上述过程类似,但是直接在ImageBuffer中改我们计算E8和E9后面的值就可以不用再将文件地址转为内存地址了,在哪里添加硬编码,直接取这个地址代到公式中进行计算即可,更方便一些,但是winhex工具目前为止无法实现,虽然可以修改,但是最后没办法保存,因为如果保存,只能保存此时的全部数据,即运行时拉伸过的全部数据到一个新的文件中,但是我们保存到硬盘上,是需要没有拉伸的,即文件对齐的,所以可以改,但是最后没法保存,不信就往下看。所以这种直接在imageBuffer中修改数据,只适合于我们自己编程的时候,因为最后改完还可以用编程C把ImageBuffer再编程newbuffer

  • 我们先通过e_lfanew字段值0xE8找到PE开始,标准PE头倒数第二个字段为SizeOfOptionalHeader,值为0xE0,所以从标准PE往后数0xE0字节,找到节表起始地址0x100001E0,我们找到Misc.VirtualSize字段值为0x6D72,再找VirtualAddress字段值为0x1000,由于文件起始地址为0x1000000(imagebase/或者直接看开头地址),那么.text节的起始地址为0x1001000,没对齐之前节本身结尾为0x1001000 + 0x6D72 = 0x1007D72,再根据下一个节表的VirtualAddress值为0x8000,可以知道,从0x1007D72到0x1008000为.text的空白区

  • 接着我们将这里E8的起始地址和MessageBoxA函数的内存地址代入公式X = 要跳转的地址 - (E8当前的内存地址 + 5),为X = 0x77D36476 - (0x1007D7A + 5) = 0x76D2E6F7;同理将E9的起始地址和程序原来的程序入口地址0x1000000 + 0x6AE0 = 0x1006AE0代入公式得E9后面跟的值为:X = 0x1006AE0 - (0x1007D7F + 5) = 0xFFFFED5C

这里就不用再进行文件地址到内存地址的换算了,直接看E8在哪个地址,这个地址就是E8的内存地址

  • 最后将程序的EOP字段的值改为此段硬编码的起始内存地址相对于imagebase的偏移量0x7D72,保存即可

  • 此时会发现没法保存,即使复制全部数据到新的文件中,也是将拉伸过的文件数据保存到了硬盘上,文件是无法运行的,所以现实中还是使用方法一比较可行,只是稍微麻烦一点,计算E8和E9后面的值是需要将文件地址转换成内存地址而已;但是如果用编码实现的话,由于我们可以写代码将文件拉伸,还可以再还原,所以写代码使用方法二更合适

任意代码空白区添加代码(自动)

#include"stdafx.h"
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<stdlib.h>
#include<windows.h>
​
#define test 1
#define SHELLCODELENGTH 0x12
#define MESSAGEBOXADDR 0x7679FEAE
​
BYTE shellcode[] = {
    0x6A,00,0x6A,00,0x6A,00,0x6A,00,
    0xE8,00,00,00,00,
    0xE9,00,00,00,00
};
​
DWORD ReadPEFile(IN LPSTR file_path,OUT PVOID* pFileBuffer);
​
DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer);
DWORD CopyImageBufferToNewFileBuffer(PVOID pImageBuffer, PVOID* pNewFileBuffer);
BOOL MemoryToFile(PVOID pMemBuffer, size_t size, LPSTR lpszFile);
​
char file_path[] = "C:\\Users\\Admin.Admin-PC\\Desktop\\ipmsg.exe";
char write_file_path[] = "C:\\Users\\Admin.Admin-PC\\Desktop\\1.exe";
​
//返回PE文件大小
DWORD ReadPEFile(IN LPSTR file_path,OUT PVOID* pFileBuffer)
{
    FILE* pFile = NULL;
    DWORD FileSize = 0;
    PVOID pFileBufferTemp = NULL;
​
    pFile = fopen(file_path, "rb");
​
    if (!pFile)
    {
        printf("(ToLoaderPE)Can't open file!\n");
        return 0;
    }
​
    fseek(pFile, 0, SEEK_END);
    FileSize = ftell(pFile);
    printf("FileBuffer: %#x\n", FileSize);
    fseek(pFile, 0, SEEK_SET);
    pFileBufferTemp = malloc(FileSize);
​
    if (!pFileBufferTemp)
    {
        printf("(ToLoaderPE)Allocate dynamic memory failed!\n");
        fclose(pFile);
        return 0;
    }
    /*将文件读取到缓冲区*/
    size_t n = fread(pFileBufferTemp, FileSize, 1, pFile);
​
    if (!n)
    {
        printf("(ToLoaderPE)Read file failed!\n");
        free(pFileBufferTemp);
        fclose(pFile);
        return 0;
    }
    *pFileBuffer = pFileBufferTemp;
    pFileBufferTemp = NULL;
    fclose(pFile);
    return FileSize;
}
​
DWORD CopyFileBufferToImageBuffer(PVOID pFileBuffer, PVOID* pImageBuffer)
{
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
​
    PVOID pImageTemp = NULL;
​
    if (!pFileBuffer)
    {
        printf("(CopyFileBufferToImageBuffer)Can't open file!\n");
        return 0;
    }
    /*判断是否为MZ标识*/
    if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
    {
        printf("No MZ flag, not exe file!\n");
        return 0;
    }
​
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
​
    if (*((LPDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    {
        printf("(CopyFileBufferToImageBuffer)Not a valid PE flag!\n");
        return 0;
    } 
​
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
​
    pImageTemp = malloc(pOptionHeader->SizeOfImage);
​
    if (!pImageTemp)
    {
        printf("(CopyFileBufferToImageBuffer)Allocate dynamic memory failed!\n");
        free(pImageTemp);
        return 0;
    }
    /*初始化新的缓冲区*/
    memset(pImageTemp, 0, pOptionHeader->SizeOfImage);
    /*根据SizeofHeaders  先Copy头*/
    memcpy(pImageTemp, pDosHeader, pOptionHeader->SizeOfHeaders);
    /*根据节表  循环Copy头*/
    PIMAGE_SECTION_HEADER pSectionHeaderTemp = pSectionHeader;
    
​
    for (int n = 0; n < pPEHeader->NumberOfSections; n++, pSectionHeaderTemp++)
    {
        memcpy((PVOID)((DWORD)pImageTemp + pSectionHeaderTemp->VirtualAddress), (PVOID)((DWORD)pFileBuffer + pSectionHeaderTemp->PointerToRawData), pSectionHeaderTemp->SizeOfRawData);
        printf("VirtualAddress%d: %#10x         PointerToRawData%d: %#10x\n", n, (DWORD)pImageTemp + pSectionHeader->VirtualAddress, n, (DWORD)pFileBuffer + pSectionHeader->PointerToRawData);
    }
    *pImageBuffer = pImageTemp;
    pImageTemp = NULL;
    return pOptionHeader->SizeOfImage;
}
​
DWORD CopyImageBufferToNewFileBuffer(PVOID pImageBuffer, PVOID* pNewFileBuffer)
{
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_NT_HEADERS pNTHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL; 
​
    LPVOID pTempNewbuffer = NULL;
    DWORD sizeofFile = 0;
    DWORD numberofSection = 0;
​
    if (!pImageBuffer)
    {
        printf("(CopyImageBufferToNewBuffer)Can't open file!\n");
        return 0;
    }
​
    if (*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
    {
        printf("(CopyImageBufferToNewBuffer)No MZ flag, not exe file!\n");
        return 0;
    }
​
    pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    if (*((PDWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
    {
        printf("(CopyImageBufferToNewBuffer)Not a valid PE flag!\n");
        return 0;
    }
​
    pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); // 这里必须强制类型转换
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
​
    //获取new_buffer的大小
    sizeofFile = pOptionHeader->SizeOfHeaders;
    
​
    for (DWORD i = 0; i < pPEHeader->NumberOfSections; i++)
    {
        sizeofFile += pSectionHeader[i].SizeOfRawData;  // pSectionHeader[i]另一种加法
    }
    // 分配内存(newbuffer)
    pTempNewbuffer = malloc(sizeofFile);
    if (!pTempNewbuffer)
    {
        printf("(CopyImageBufferToNewBuffer)Allocate dynamic memory failed!\n");
        free(pTempNewbuffer);
        return 0;
    }
    memset(pTempNewbuffer, 0, sizeofFile);
​
    memcpy(pTempNewbuffer, pDosHeader, pOptionHeader->SizeOfHeaders);
    // 循环拷贝节区
    PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;
    
    for (DWORD j = 0; j < pPEHeader->NumberOfSections; j++, pTempSectionHeader++)
    {   //PointerToRawData节区在文件中的偏移,VirtualAddress节区在内存中的偏移地址,SizeOfRawData节在文件中对齐后的尺寸
        memcpy((PVOID)((DWORD)pTempNewbuffer + pTempSectionHeader->PointerToRawData), (PVOID)((DWORD)pImageBuffer + pTempSectionHeader->VirtualAddress), pTempSectionHeader->SizeOfRawData);
    }
    //返回数据
    *pNewFileBuffer = pTempNewbuffer; //暂存的数据传给参数后释放
    pTempNewbuffer = NULL;
    return sizeofFile;  // 返回计算得到的分配内存的大小
}
​
​
​
BOOL MemoryToFile(PVOID pMemBuffer, size_t size, LPSTR lpszFile)
{
    FILE* fp=NULL;
    fp = fopen(lpszFile, "wb");
    if (fp == NULL)
    {
        return FALSE;
    }
    fwrite(pMemBuffer, size, 1, fp);
    fclose(fp);
    fp = NULL;
    return TRUE;
}
/*
VOID operate()
{
    LPVOID pFileBuffer = NULL;
    LPVOID pNewFileBuffer = NULL;
    LPVOID pImageBuffer = NULL;
​
    DWORD ret1 = ReadPEFile(file_path, &pFileBuffer);  // &pFileBuffer(void**类型) 传递地址对其值可以进行修改
    printf("exe->filebuffer  返回值为计算所得文件大小:%#x\n", ret1);
​
    DWORD ret2 = CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
    printf("filebuffer -> imagebuffer返回值为计算所得文件大小:%#x\n", ret2);
    DWORD ret3 = CopyImageBufferToNewFileBuffer(pImageBuffer, &pNewFileBuffer);
    printf("imagebuffer -> newfilebuffer返回值为计算所得文件大小:%#x\n", ret3);
    MemoryToFile(pNewFileBuffer, ret3, write_file_path);
​
    free(pFileBuffer);
    free(pNewFileBuffer);
    free(pImageBuffer);
}*/
VOID TestAddCodeInCodeSec()
{
    PVOID pFileBuffer = NULL;
    PVOID pImageBuffer = NULL;
    PVOID pNewBuffer = NULL;
    PIMAGE_DOS_HEADER pDosHeader = NULL;
    PIMAGE_FILE_HEADER pPEHeader = NULL;
    PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
    PIMAGE_SECTION_HEADER pSectionHeader = NULL;
    PBYTE codeBegin = NULL;
    BOOL isOk = FALSE;
    DWORD size = 0;
    /*File->fileBuffer*/
    ReadPEFile(file_path, &pFileBuffer);
    if (!pFileBuffer)
    {
        printf("文件-缓冲区失败");
        return;
    }
    /*FileBuffer->ImageBuffer*/
    CopyFileBufferToImageBuffer(pFileBuffer, &pImageBuffer);
    if (!pImageBuffer)
    {
        printf(" 复制文件到缓冲区失败");
        free(pFileBuffer);
        return ;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
    pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)((DWORD)pImageBuffer + pDosHeader->e_lfanew)+4);
    pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER);
    pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer + pDosHeader->e_lfanew) + 4 + IMAGE_SIZEOF_FILE_HEADER + pPEHeader->SizeOfOptionalHeader);
    if (((pSectionHeader->SizeOfRawData) - (pSectionHeader->Misc.PhysicalAddress)) < SHELLCODELENGTH)
    {
        printf("代码空间不够");
        free(pFileBuffer);
        free(pImageBuffer);
        return;
    }
    //将代码复制到空闲区
    codeBegin = (PBYTE)((DWORD)pImageBuffer + pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize);
    memcpy(codeBegin, shellcode, SHELLCODELENGTH);
    //修正E8
    DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase + ((DWORD)(codeBegin + 0xD) - (DWORD)pImageBuffer)));
    *(PDWORD)(codeBegin + 9) = callAddr;
    //修正E9
    DWORD jmpAddr = ((pOptionHeader->AddressOfEntryPoint + pOptionHeader->ImageBase) - (pOptionHeader->ImageBase+((DWORD)(codeBegin + SHELLCODELENGTH) - (DWORD)pImageBuffer)));
    *(PDWORD)(codeBegin + 0xE) = jmpAddr;
    //修改OEP
    pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer;
    //ImageBuffer->NewBuffer
    size = CopyImageBufferToNewFileBuffer(pImageBuffer, &pNewBuffer);
    if (size == 0||!pNewBuffer)
    {
        printf("存盘失败");
        free(pFileBuffer);
        free(pImageBuffer);
        free(pNewBuffer);
        return;
    }
    isOk = MemoryToFile(pNewBuffer, size, write_file_path);
    if (isOk)
    {
        printf("存盘成功");
        return;
    }
    free(pFileBuffer);
    free(pImageBuffer);
    free(pNewBuffer);
    return;
}
int main()
{
    TestAddCodeInCodeSec();
    getchar();
    return 0;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
第1讲:2015-01-12(进制01) 第2讲:2015-01-13(进制02) 第3讲:2015-01-14(数据宽度-逻辑运算03) 第4讲:2015-01-15(通用寄存器-内存读写04) 第5讲:2015-01-16(内存寻址-堆栈05) 第6讲:2015-01-19(EFLAGS寄存器06) 第7讲:2015-01-20(JCC) 第8讲:2015-01-21(堆栈图) 第8讲:2015-01-21(宝马问题) 第9讲:2015-01-22(堆栈图2) 第10讲:2015-01-23(C语言01_后半段) 第10讲:2015-01-23(C语言完整版) 第11讲:2015-01-26(C语言02_数据类型) 第12讲:2015-01-27(C语言03_数据类型_IF语句) 第13讲:2015-01-28(C语言04_IF语句逆向分析上) 第14讲:2015-01-28(C语言04_IF语句逆向分析下) 第15讲:2015-01-29(C语言04_正向基础) 第16讲:2015-01-30(C语言05_循环语句) 第17讲:2015-02-02(C语言06_参数_返回值_局部变量_数组反汇编) 第18讲:2015-02-02(2015-01-30课后练习) 第19讲:2015-02-03(C语言07_多维数组) 第20讲:2015-02-03(2015-02-02课后练习) 第21讲:2015-02-04(C语言08_结构体) 第22讲:2015-02-05(C语言09_字对齐_结构体数组) 第23讲:2015-02-06(C语言10_Switch语句反汇编) 第24讲:2015-02-26(C语言11_指针1) 第25讲:2015-02-27(C语言11_指针2) 第26讲:2015-02-28(C语言11_指针3) 第27讲:2015-02-28(C语言11_指针4) 第28讲:2015-03-02(C语言11_指针5) 第29讲:2015-03-03(C语言11_指针6) 第30讲:2015-03-04(C语言11_指针7) 第31讲:2015-03-06(C语言11_指针8) 第32讲:2015-03-09(位运算) 第33讲:2015-03-10(内存分配_文件读写) 第34讲:2015-03-11(PE头解析_手动) 第35讲:2015-03-12(PE头字段说明) 第36讲:2015-03-13(PE表) 第37讲:2015-03-16(FileBuffer转ImageBuffer) 第38讲:2015-03-17(代码空白添加代码) 第39讲:2015-03-18(任意空白添加代码) 第40讲:2015-03-19(新增添加代码) 第41讲:2015-03-20(扩大-合并-数据目录) 第42讲:2015-03-23(静态连接库-动态链接库) 第43讲:2015-03-24(导出表) 第44讲:2015-03-25(重定位表) 第45讲:2015-03-26(移动导出表-重定位表) 第46讲:2015-03-27(IAT表) 第47讲:2015-03-27(导入表) 第48讲:2015-03-30(绑定导入表) 第49讲:2015-03-31(导入表注入) 第50讲:2015-04-01(C++ this指针 类 上) 第51讲:2015-04-01(C++ this指针 类 下) 第52讲:2015-04-02(C++ 构造-析构函数 继承) 第53讲:2015-04-03(C++ 权限控制) 第54讲:2015-04-07(C++ 虚函数表) 第55讲:2015-04-08(C++ 动态绑定-多态-上) 第56讲:2015-04-08(C++ 动态绑定-多态-下) 第57讲:2015-04-09(C++ 模版) 第58讲:2015-04-10(C++ 引用-友元-运算符重载) 第59讲:2015-04-13(C++ new-delete-Vector) 第60讲:2015-04-14(C++Vector实现) 第61讲:2015-04-15(C++链表) 第62讲:2015-04-16(C++链表实现) 第63讲:2015-04-16(C++二叉树) 第64讲:2015-04-17(C++二叉树实现) 第65讲:2015-04-20(Win32 宽字符) 第66讲:2015-04-21(Win32 事件-消息-消息处理函数) 第67讲:2015-04-22(Win32 ESP寻址-定位回调函数-条件断点) 第68讲:2015-04-23(Win32 子窗口-消息处理函数定位) 第69讲:2015-04-24(Win32 资源文件-消息断点) 第70讲:2015-04-27(Win32 提取图标-修改标题) 第71讲:2015-04-28(Win32 通用控件-VM_NOTIFY) 第72讲:2015-04-29(Win32 PE查看器-项目要求) 项目一:PE查看器 开发周期(5天) 需求文档 第73讲:2015-05-07(Win32 创建线程) 第74讲:2015-05-08(Win32 线程控制_CONTEXT) 第75讲:2015-05-11(Win32 临界) 第76讲:2015-05-12(Win32 互斥体) 第77讲:2015-05-13(Win32 事件) 第78讲:2015-05-14(Win32 信号量) 第79讲:2015-05-15(Win32 线程同步与线程互斥) 第80讲:2015-05-18(Win32 进程创建_句柄表) 第81讲:2015-05-20(Win32 以挂起形式创建进程) 第82讲:2015-05-21(Win32 加密壳_项目说明) 项目二:加密壳 开发周期(5天) 需求文档 第83讲:2015-05-28(Win32 枚举窗口_鼠标键盘事件) 第84讲:2015-05-29(Win32 CE练习) 第85讲:2015-06-01(Win32 OD练习) 第86讲:2015-06-03(Win32 ShellCode_远程线程注入) 第87讲:2015-06-04(Win32 加载EXE_模块隐藏) 第88讲:2015-06-09(Win32 IAT_HOOK) 第89讲:2015-06-10(Win32 InlineHook) 第90讲:2015-06-11(Win32 进程通信) 第91讲:2015-06-11(Win32 进程监控_项目说明) 项目三:进程监控 开发周期(5天) 需求文档 第92讲:2015-06-15(硬编码_01) 第93讲:2015-06-16(硬编码_02) 第94讲:2015-06-17(硬编码_03) 第95讲:2015-06-18(硬编码_04) 第96讲:2015-06-19(硬编码_05)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值