PE结构-空白区手动添加任意代码(附实例代码)

预备知识

汇编命令硬编码
callE8 00 00 00 00
jmpE9 00 00 00 00
push6A 00

需要添加的代码:

6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00 
//前面四个6A硬编码代表的是传入的参数,E8为Call E9为jmp
//大小为18个字节

1.查找本机MessageBoxA地址

1.打开OD调试工具拖入要添加的exe程序。

注意必须是有user32.dll的exe否则没有MessageA函数地址

在这里插入图片描述

2.在命令中输入 : (输入后按下回车键)
bp MessageBoxA

在这里插入图片描述

3.点击断点页面即可看到MessageBoxA 的地址

地址=76F81060 模块/标签/异常=<user32.dll.MessageBoxA> 状态=已启用 反汇编=mov edi,edi

在这里插入图片描述

开始添加代码

1.查看要添加的文件空白区大小是否足够

使用PETool载入exe 查看pe结构任意节表空白区
在这里插入图片描述
空白区还剩下566个字节是够用的。

2.打开16进制编辑器,载入要修改的EXE。找到文件中的大小(对齐后的长度的位置+ 文件中偏移的位置) (1C000 + 1000 = 1d000)

需要添加的代码:

6A 00 6A 00 6A 00 6A 00 E8 00 00 00 00 E9 00 00 00 00 
//前面四个6A硬编码代表的是传入的参数,E8为Call E9为jmp
//大小为18个字节

在这里插入图片描述

3.在1d000位置上面找任意一段空白区添加上代码 (最好是添加到 空白区开始预留一行的位置,便于以后再添加更多代码节约空间)

在这里插入图片描述
往上翻以后发现这个区段从1cab0开始就已经是空白区了那就添加到1cab0这个位置吧
在这里插入图片描述

计算E8跳转的地址

公式:
真正要跳转的地址 = E8这条指令的下一行地址 + x(E8后面跟的值)
x = 真正要跳转的地址 - E8这条指令的下一行的地址
要跳转的地方 = E8当前的地址 + 5 + x
x = 要跳转的地址 - (E8的地址 + 5)(上面三行可以不用管,重点看这行就行)

这里我们要跳转的地址为MessageBoxA的地址在上面已经教大家查找过了:
MessageBoxA的地址(要跳转的地址) = 76F81060 (内存中的地址)
(E8的地址 + 5) = 1cabd (文件中的地址)
(E8的地址 + 5) 即 E8下一行的地址,如图:
在这里插入图片描述
由于 1cabd 是文件中的地址,还要进行一次转换,变成内存中的地址。
即 1cabd + ImageBase (1cabd + 00400000)= 41cabd
在这里插入图片描述

x = 76F81060 - 41cabd = 76B6 45A3

E8 A3 45 B6 76
//内存中字节是大端存储的,所以是倒序。

在这里插入图片描述

修改OEP (程序入口的点)

原始入口点为:

BE 93 01

要修改的入口点为:

01 CA B0
写入到文件用大端存储 :B0 CA 01

修改前为:
在这里插入图片描述
在这里插入图片描述
修改后为:
在这里插入图片描述
修改完成后保存文件,双击exe测试是否修改正确如图:
在这里插入图片描述
但是此时不会转到正确的软件界面。因为我们还没有计算E9该跳转的位置。

x = 01 93 BE +(400000) - 41cac2
x = 4193be - 41cac2 = FFFFC8FC
//原始入口点(在内存中开始的位置)减去跳转的下一行地址
E8 FC C8 BF FF
//内存中字节是大端存储的,所以是倒序。
在这里插入图片描述

完成后效果演示:

在这里插入图片描述

实例代码
#define MessageBoxAToState 0x75031060

char INFILEPATH[] = "D:\\PETool 1.0.0.5.exe";

char OUTFILEPATH[] = "D:\\PETool 1.0.0.5(1).exe";

const char SHELLCODE[] = { 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00,
						   0xE8, 0x00, 0x00, 0x00, 0x00,
						   0xE9, 0x00, 0x00, 0x00, 0x00 };
//**************************************************************************								
//AddImageBufferToShellCode:将FileBuffer中添加恶意代码								
//参数说明:								
//pFileBuffer FileBuffer指针								
//pNewBuffer NewBuffer指针
//pShellCode ShellCode指针
//返回值说明:								
//读取失败返回false  否则返回true							
//**************************************************************************	



BOOL AddFileBufferToShellCode(IN OUT LPVOID pFileBuffer, IN const char* pShellCode, IN size_t ShellCodeSize)
{
	//DOC头
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	//节表解析
	PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	//计算空间是否足够
	DWORD whiteSpaceSize = 0;
	for (int i = 0; i < pPEHeader->NumberOfSections; i++)
	{
		//计算对其前的长度和对其后的长度,判断空白区域是否足够
		whiteSpaceSize = pSectionHeader->SizeOfRawData - pSectionHeader->Misc.VirtualSize;
		if (sizeof(*pShellCode) + 16 < whiteSpaceSize)
		{
			printf("%s: %d  %s %d \n", "节表", i, "空白区域剩余:", whiteSpaceSize);
			//开始添加ShellCode
			char* pShellCodeAddress = (char*)pFileBuffer;
			pShellCodeAddress = pShellCodeAddress + (pSectionHeader->Misc.VirtualSize + pSectionHeader->VirtualAddress) + 22;
			memcpy(pShellCodeAddress, pShellCode, ShellCodeSize);
			//AddCharacterCompressionToMemory(pShellCode, shellCodeSize, pShellCodeBuffer); //如果是字符串用这个
			//计算E8   x = 要跳转的地址 - (E8的地址 + 5)
			int e8CallAddress =  MessageBoxAToState - ((int)(pShellCodeAddress + 0xd) - (int)pFileBuffer + pOptionHeader->ImageBase);
			*(int*)(pShellCodeAddress + 0x9) = e8CallAddress;
			//计算E9   x = 要跳转的地址 - (E8的地址 + 5)
			int e9CallAddress = (pOptionHeader->AddressOfEntryPoint + pOptionHeader->ImageBase) - ((int)(pShellCodeAddress + 0x12 - (int)pFileBuffer) + pOptionHeader->ImageBase);
			*(int*)(pShellCodeAddress + 0xe) = e9CallAddress;
			//修改OEP
			pOptionHeader->AddressOfEntryPoint = (pShellCodeAddress - (char*)pFileBuffer);
			pShellCodeAddress = nullptr;
			return true;
		}
		else
		{
			printf("%s: %d  %s \n", "节表", i, "空白区域不足!");
		}
		pSectionHeader++;
	}
	return false;
}

实例代码测试图

在这里插入图片描述

开源地址:

源代码: https://github.com/vShellCode/Analysis-of-PE-structure
觉得不错请给个star!

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
PETools 源码 // ImportTable.cpp : implementation file // #include "stdafx.h" #include "PEinfo by saga.h" #include "ImportTable.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CImportTable dialog CImportTable::CImportTable(CWnd* pParent /*=NULL*/) : CDialog(CImportTable::IDD, pParent) { //{{AFX_DATA_INIT(CImportTable) //}}AFX_DATA_INIT } void CImportTable::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CImportTable) DDX_Control(pDX, IDC_LIST2, m_ListCtrl2); DDX_Control(pDX, IDC_LIST1, m_ListCtrl1); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CImportTable, CDialog) //{{AFX_MSG_MAP(CImportTable) ON_NOTIFY(NM_CLICK, IDC_LIST1, OnClickList1) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CImportTable message handlers BOOL CImportTable::OnInitDialog() { // TODO: Add extra initialization here CDialog::OnInitDialog(); CFile PEfile,PEfile2; WORD NumofSection; DWORD n,j,ImpRVA,ImpRaw,NameRaw; char cBuff[1024]; IMAGE_IMPORT_DESCRIPTOR ImpDescriptor; if (!PEfile.Open(CPEinfo::FilePathName.GetBuffer(CPEinfo::\ FilePathName.GetLength()),CFile::shareDenyNone)) { MessageBox("无法打开文件!"); return TRUE; } else{ PEfile.Seek(CPEinfo::DosHeader.e_lfanew,CFile::begin); PEfile.Seek(sizeof(CPEinfo::NtHeader),CFile::current); } if (!PEfile2.Open(CPEinfo::FilePathName.GetBuffer(CPEinfo::\ FilePathName.GetLength()),CFile::shareDenyNone)) { MessageBox("无法打开文件!"); return TRUE; } this->m_ListCtrl1.InsertColumn(0,"DLL Name",LVCFMT_LEFT,80); this->m_ListCtrl1.InsertColumn(1,"OriginalFirstThunk",LVCFMT_LEFT,98); this->m_ListCtrl1.InsertColumn(2,"TimeDateStamp",LVCFMT_LEFT,94); this->m_ListCtrl1.InsertColumn(3,"ForwarderChain",LVCFMT_LEFT,94); this->m_ListCtrl1.InsertColumn(4,"Name",LVCFMT_LEFT,90); this->m_ListCtrl1.InsertColumn(5,"FirstThunk",LVCFMT_LEFT,94); this->m_ListCtrl1.SetExtendedStyle(LVS_EX_FULLROWSELECT); this->m_ListCtrl2.InsertColumn(0,"ThunkRVA",LVCFMT_LEFT,90); this->m_ListCtrl2.InsertColumn(1,"ThunkValue",LVCFMT_LEFT,90); this->m_ListCtrl2.InsertColumn(2,"Hint",LVCFMT_LEFT,50); this->m_ListCtrl2.InsertColumn(3,"Function Name",LVCFMT_LEFT,300); this->m_ListCtrl2.SetExtendedStyle(LVS_EX_FULLROWSELECT); NumofSection=CPEinfo::NtHeader.FileHeader.NumberOfSections; ImpRVA=CPEinfo::NtHeader.OptionalHeader.DataDirectory[1].VirtualAddress; for(n=NumofSection;n>0;n--){ PEfile.Read(&CPEinfo;::SecHeader,sizeof(CPEinfo::SecHeader)); if (ImpRVA<(CPEinfo::SecHeader.VirtualAddress+\ CPEinfo::SecHeader.Misc.VirtualSize)) { ImpRaw=ImpRVA-CPEinfo::SecHeader.VirtualAddress\ +CPEinfo::SecHeader.PointerToRawData; break; } } PEfile.Seek(ImpRaw,CFile::begin); n=0; while (TRUE) { PEfile.Read(&ImpDescriptor;,20); if (ImpDescriptor.Name==NULL) { break; } else { NameRaw=ImpDescriptor.Name-ImpRVA+ImpRaw; PEfile2.Seek(NameRaw,CFile::begin); for(j=0;j<1024;j++){ PEfile2.Read(&cBuff;[j],1); if (cBuff[j]==NULL) { break; } } this->m_ListCtrl1.InsertItem(n,cBuff); wsprintf(cBuff,"lX",ImpDescriptor.OriginalFirstThunk); this->m_ListCtrl1.SetItemText(n,1,cBuff); wsprintf(cBuff,"lX",ImpDescriptor.TimeDateStamp); this->m_ListCtrl1.SetItemText(n,2,cBuff); wsprintf(cBuff,"lX",ImpDescriptor.ForwarderChain); this->m_ListCtrl1.SetItemText(n,3,cBuff); wsprintf(cBuff,"lX",ImpDescriptor.Name); this->m_ListCtrl1.SetItemText(n,4,cBuff); wsprintf(cBuff,"lX",ImpDescriptor.FirstThunk); this->m_ListCtrl1.SetItemText(n,5,cBuff); n++; } } PEfile.Close(); PEfile2.Close(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CImportTable::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult) { // TODO: Add your control notification handler code here POSITION SelectItemNum; char cBuff[1024]; CFile PEfile,PEfile2; DWORD n,j,ImpRVA,ImpRaw,IATRaw,NameRaw; WORD NumofSection,Hint; IMAGE_IMPORT_DESCRIPTOR ImpDescriptor; IMAGE_THUNK_DATA ThunkData; if (!PEfile.Open(CPEinfo::FilePathName.GetBuffer(CPEinfo::\ FilePathName.GetLength()),CFile::shareDenyNone)) { MessageBox("无法打开文件!"); return; } else{ PEfile.Seek(CPEinfo::DosHeader.e_lfanew,CFile::begin); PEfile.Seek(sizeof(CPEinfo::NtHeader),CFile::current); } if (!PEfile2.Open(CPEinfo::FilePathName.GetBuffer(CPEinfo::\ FilePathName.GetLength()),CFile::shareDenyNone)) { MessageBox("无法打开文件!"); return; } NumofSection=CPEinfo::NtHeader.FileHeader.NumberOfSections; ImpRVA=CPEinfo::NtHeader.OptionalHeader.DataDirectory[1].VirtualAddress; for(n=NumofSection;n>0;n--){ PEfile.Read(&CPEinfo;::SecHeader,sizeof(CPEinfo::SecHeader)); if (ImpRVA<(CPEinfo::SecHeader.VirtualAddress+CPEinfo::SecHeader.Misc.VirtualSize)) { ImpRaw=ImpRVA-CPEinfo::SecHeader.VirtualAddress +CPEinfo::SecHeader.PointerToRawData; break; } } PEfile.Seek(ImpRaw,CFile::begin); if ((SelectItemNum=this->m_ListCtrl1.GetFirstSelectedItemPosition())==NULL) { return; } this->m_ListCtrl2.DeleteAllItems(); j=DWORD(SelectItemNum); for(n=0;n<j;n++){ PEfile.Read(&ImpDescriptor;,20); } //wsprintf(cBuff,"lX",ImpDescriptor.Name); //MessageBox(cBuff); IATRaw=ImpDescriptor.FirstThunk-ImpRVA+ImpRaw; PEfile.Seek(IATRaw,CFile::begin); n=0; while (TRUE){ PEfile.Read(&ThunkData;,4); if (ThunkData.u1.AddressOfData==NULL) { break; } wsprintf(cBuff,"lX",ImpDescriptor.FirstThunk); this->m_ListCtrl2.InsertItem(n,cBuff); wsprintf(cBuff,"lX",ThunkData); this->m_ListCtrl2.SetItemText(n,1,cBuff); if (((DWORD)ThunkData.u1.AddressOfData&0x80000000;)==0x80000000) { this->m_ListCtrl2.SetItemText(n,2,"--"); this->m_ListCtrl2.SetItemText(n,3,"--"); } else{ NameRaw=(DWORD)ThunkData.u1.AddressOfData-ImpRVA+ImpRaw; PEfile2.Seek(NameRaw,CFile::begin); PEfile2.Read(&Hint;,2); wsprintf(cBuff,"lX",Hint); this->m_ListCtrl2.SetItemText(n,2,cBuff); for(j=0;j<1024;j++){ PEfile2.Read(&cBuff;[j],1); if (cBuff[j]==NULL) { break; } } this->m_ListCtrl2.SetItemText(n,3,cBuff); } ImpDescriptor.FirstThunk+=4; n++; } PEfile.Close(); PEfile2.Close(); *pResult = 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值