本节主要讲 通过添加新区块、修改输入表方法实现PE感染
本次课程涉及到的技术点有几个部分:
1,添加输入表项。
2,添加新区块。
3,插入 Stub。
********************************************************************************************
下面是实现这个程序的主要步骤,其中使用内存映射机制来实现文件的操作。
1)添加用于存放Stub的新区块。添加新区块需要进行一下操作:
增加区块数量
添加区块信息
修正PE文件的映像大小
添加PE文件大小
********************************************************************************************
Stub 要完成的任务很简单,显示消息框然后跳转到应用程序原始入口继续执行。
需要修改程序的入口点指向 Stub ,应用程序执行时就会直接转到 Stub 执行。
********************************************************************************************
新区块数据由以下7本分组成:
1,输入表,原输入表数据复制到新区块,并为user32.dll的MessageBoxA加新项。
2,DLL名字符串,固定为“USER32.dll”,在输入表新项中使用。
3,函数名字符串,固定为“MessageBoxA”,在输入表新项中使用。
4,新输入表项所对应的IAT表。
5,Nag消息框的标题字符串。
6,Nag消息框的内容字符串。
以下为完整代码:
PEInfo.h文件
#pragma once typedef struct _MAP_ITEM { HANDLE hFile ; HANDLE hMapFile ; LPVOID lpMapAddr ; } MAP_ITEM ; typedef MAP_ITEM* PMAP_ITEM ; typedef struct _BASE_INFO_ITEM { DWORD dwSectionAlign ; //块对齐大小 DWORD dwFileAlign ; //文件块对齐大小 WORD dwSectionBase ; //节表开始地址 WORD dwSectionNum ; //节表个数 DWORD dwHeadSize ; //所有头+节表大小,也可以以此值作为PE文件第一节的文件偏移量 DWORD dwRealHeadSize ; //节表结束地址 DWORD dwImageSize ; //镜像大小 DWORD dwFileSize ; //文件大小 } BASE_INFO_ITEM ; typedef BASE_INFO_ITEM* PBASE_INFO_ITEM ; class CPEInfo { public: CPEInfo(void); public: ~CPEInfo(void); public: BOOL isReady ; BASE_INFO_ITEM BaseInfo ; IMAGE_SECTION_HEADER NewSection ; public: BOOL CreateMap ( TCHAR* pPathName, PMAP_ITEM pMapItem ) ; BOOL CreateNewMap ( TCHAR* pPathName, PMAP_ITEM pMapItem, DWORD dwFileSize ) ; VOID DeleteMap ( PMAP_ITEM pMapItem ) ; BOOL FlushData ( LPVOID lpAddr, UINT nNumToFlush ) ;//清除数据 public: BOOL IsValidPE ( PMAP_ITEM pMapItem ) ; VOID GetBaseInfo ( PMAP_ITEM pMapItem ) ; VOID InitNewSection () ; //初始的新Section VOID AdjustSectionSize () ; // 包含了映像大小和文件大小 VOID AddNewSection ( PMAP_ITEM pOldMap, PMAP_ITEM pNewMap, DWORD dwNewFileSize ) ; public: DWORD FormatInt ( DWORD dwValue, DWORD dwAlign ) ; };
PEInfo.cpp
#include "StdAfx.h" #include "PEInfo.h" CPEInfo::CPEInfo(void) { int ii = sizeof(IMAGE_OPTIONAL_HEADER); isReady = FALSE ; memset ( &BaseInfo, 0, sizeof(BASE_INFO_ITEM) ) ;//新申请的内存做初始化工作 memset ( &NewSection, 0, sizeof(IMAGE_SECTION_HEADER) ) ;//新申请的内存做初始化工作 } CPEInfo::~CPEInfo(void) { } BOOL CPEInfo::CreateMap ( TCHAR* pPathName, PMAP_ITEM pMapItem ) { pMapItem->hFile = CreateFile ( pPathName, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL ); if ( pMapItem->hFile == INVALID_HANDLE_VALUE ) { return FALSE; } //创建文件映射内核对象 pMapItem->hMapFile = CreateFileMapping ( pMapItem->hFile, NULL, PAGE_READONLY, 0, 0, NULL ) ; if ( pMapItem->hMapFile == NULL ) { CloseHandle ( pMapItem->hFile ) ; return FALSE; } //创建文件视图 pMapItem->lpMapAddr = (PBYTE)MapViewOfFile ( pMapItem->hMapFile, FILE_MAP_READ, 0, 0, 0 ) ; if ( pMapItem->lpMapAddr == NULL ) { DWORD dwErrorCode = GetLastError () ; CloseHandle ( pMapItem->hMapFile ) ; CloseHandle ( pMapItem->hFile ) ; return FALSE; } return TRUE ; } BOOL CPEInfo::CreateNewMap ( TCHAR* pPathName, PMAP_ITEM pMapItem, DWORD dwFileSize ) { pMapItem->hFile = CreateFile ( pPathName, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL ); if ( pMapItem->hFile == INVALID_HANDLE_VALUE ) { return FALSE; } //创建文件映射内核对象 pMapItem->hMapFile = CreateFileMapping ( pMapItem->hFile, NULL, \ PAGE_READWRITE, 0, dwFileSize, NULL ) ; if ( pMapItem->hMapFile == NULL ) { CloseHandle ( pMapItem->hFile ) ; return FALSE; } //创建文件视图 pMapItem->lpMapAddr = (PBYTE)MapViewOfFile ( pMapItem->hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 ) ; if ( pMapItem->lpMapAddr == NULL ) { DWORD dwErrorCode = GetLastError () ; CloseHandle ( pMapItem->hMapFile ) ; CloseHandle ( pMapItem->hFile ) ; return FALSE; } return TRUE ; } void CPEInfo::DeleteMap ( PMAP_ITEM pMapItem ) { UnmapViewOfFile ( pMapItem->lpMapAddr ) ; CloseHandle ( pMapItem->hMapFile ) ; CloseHandle ( pMapItem->hFile ) ; } BOOL CPEInfo::FlushData ( LPVOID lpAddr, UINT nNumToFlush ) { return FlushViewOfFile ( lpAddr, nNumToFlush ) ; } BOOL CPEInfo::IsValidPE ( PMAP_ITEM pMapItem ) { return TRUE ; } VOID CPEInfo::GetBaseInfo ( PMAP_ITEM pMapItem ) { PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(pMapItem->lpMapAddr) ; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((LONG)(pMapItem->lpMapAddr)+ (pDosHeader->e_lfanew)) ; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader) ; BaseInfo.dwSectionAlign = pOptionalHeader->SectionAlignment ;// 内存中的区块的对齐大小 BaseInfo.dwFileAlign = pOptionalHeader->FileAlignment ;// 文件中的区块的对齐大小 BaseInfo.dwSectionNum = pNtHeader->FileHeader.NumberOfSections ;//PE文件中有多少个节 BaseInfo.dwHeadSize = pOptionalHeader->SizeOfHeaders ;// 所有头 + 区块表的尺寸大小 BaseInfo.dwSectionBase = pDosHeader->e_lfanew + 0x18 + pNtHeader->FileHeader.SizeOfOptionalHeader;//块表开始的地址DOS_Header+File__Header+Optional Header BaseInfo.dwRealHeadSize = BaseInfo.dwSectionBase + BaseInfo.dwSectionNum * 0x28 ;//块表结束的地址 BaseInfo.dwImageSize = pOptionalHeader->SizeOfImage ; PIMAGE_SECTION_HEADER LastSec = (PIMAGE_SECTION_HEADER)((LONG)(pMapItem->lpMapAddr) + BaseInfo.dwSectionBase + 0x28 * ( BaseInfo.dwSectionNum - 1 ) ) ; BaseInfo.dwFileSize = LastSec->PointerToRawData + FormatInt ( LastSec->SizeOfRawData, pOptionalHeader->FileAlignment );//文件的大小 } VOID CPEInfo::InitNewSection () { strcpy ( (char*)NewSection.Name, ".NewSec" ) ; NewSection.Misc.VirtualSize = BaseInfo.dwSectionAlign ; NewSection.VirtualAddress = BaseInfo.dwImageSize ; NewSection.SizeOfRawData = BaseInfo.dwFileAlign ; NewSection.PointerToRawData = BaseInfo.dwFileSize ; NewSection.Characteristics = 0xE0000020 ; } DWORD CPEInfo::FormatInt ( DWORD dwValue, DWORD dwAlign ) { if ( dwValue % dwAlign ) return ( dwValue / dwAlign + 1 ) * dwAlign ; return dwValue / dwAlign * dwAlign ; } void CPEInfo::AdjustSectionSize () { if ( NewSection.Misc.VirtualSize < NewSection.SizeOfRawData ) NewSection.Misc.VirtualSize = NewSection.SizeOfRawData ; if ( NewSection.Misc.VirtualSize % BaseInfo.dwSectionAlign ) NewSection.Misc.VirtualSize = NewSection.Misc.VirtualSize / BaseInfo.dwSectionAlign + 1 ; else NewSection.Misc.VirtualSize = NewSection.Misc.VirtualSize / BaseInfo.dwSectionAlign ; NewSection.Misc.VirtualSize *= BaseInfo.dwSectionAlign ; if ( NewSection.SizeOfRawData % BaseInfo.dwFileAlign ) NewSection.SizeOfRawData = NewSection.SizeOfRawData / BaseInfo.dwFileAlign + 1 ; else NewSection.SizeOfRawData = NewSection.SizeOfRawData / BaseInfo.dwFileAlign ; NewSection.SizeOfRawData *= BaseInfo.dwFileAlign ; } void CPEInfo::AddNewSection ( PMAP_ITEM pOldMap, PMAP_ITEM pNewMap, DWORD dwNewFileSize ) { memcpy ( LPVOID(pNewMap->lpMapAddr), LPVOID(pOldMap->lpMapAddr), NewSection.PointerToRawData ) ; // Fix PE Head's some item PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(pNewMap->lpMapAddr) ; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((LONG)(pNewMap->lpMapAddr)+ (pDosHeader->e_lfanew)) ; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader) ; // Increase section numbers pNtHeader->FileHeader.NumberOfSections ++ ; // Write into new IMAGE_SECTION_HEADER memcpy ( LPVOID(DWORD(pDosHeader)+BaseInfo.dwRealHeadSize), &(NewSection), 0x28 ) ; // Modify IMAGE SIZE pOptionalHeader->SizeOfImage += NewSection.Misc.VirtualSize ; FlushData ( pNewMap->lpMapAddr, dwNewFileSize ) ; }
NagGenDlg.h文件
#pragma once
#include "PEInfo.h"
#include "Dbghelp.h"
#pragma comment ( lib, "Dbghelp.lib" )
// CNagGenDlg 对话框
class CNagGenDlg : public CDialog
{
public:
CPEInfo PEInfo ;
DWORD dwDllNameOff, dwFunNameOff, dwIATOff, dwIIDNum, dwNewEntryOff, dwNagTitleOff, dwNagContentOff ;
CString m_NagTitle;
#include "stdafx.h" #include "NagGen.h" #include "NagGenDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif #define MAX_BUF_SIZE 2048 #define MAX_TITLE_SIZE 64 #define MAX_CONTENT_SIZE 256 TCHAR a[] = TEXT("fjda") ; TCHAR b[] = TEXT("fdsadagfdsa") ; // //void StubCode () //{ // PTCHAR pTitle = NULL ; // PTCHAR pContent = NULL ; // // DWORD begin, end ; // __asm // { // push edx // call $+5 // pop edx // add edx, 7 // mov begin, edx //BEGIN: // pushad // push 0 // push pTitle // push pContent // push 0 // call dword ptr MessageBoxW // popad //END: // call $+5 // pop edx // add edx, -5 // mov end, edx // pop edx // } //} void CNagGenDlg::OnBnClickedOk() { MAP_ITEM OldMap = {0}, NewMap = {0} ;//初始化数据 TCHAR pBuf[MAX_BUF_SIZE] = {0} ; BYTE pData[MAX_BUF_SIZE] ={0} ; wsprintf ( pBuf, m_PathName.GetBuffer(m_PathName.GetLength()) ) ;//m_PathName需要修改的PE文件 if ( PEInfo.CreateMap(pBuf, &OldMap) == FALSE ) //创建文件映射到内存 { MessageBox ( TEXT("Please ensure this file is not been used!") ) ; return ; } // 取得PE文件基本信息 PEInfo.GetBaseInfo (&OldMap) ; // 初始化新区段信息 PEInfo.InitNewSection () ; // 产生并组合数据,保存到pData缓冲区,并根据所需要的长度对区段信息进行调整 DWORD dwNeedSize = GenerateData ( pData, OldMap.lpMapAddr );//生成数据 if ( PEInfo.NewSection.SizeOfRawData < dwNeedSize )//判断所需的大小,并确定大小 PEInfo.NewSection.SizeOfRawData = dwNeedSize ; PEInfo.AdjustSectionSize () ; // 建立新文件(*_nag.exe) CString TempStr = m_PathName ; DWORD dwNewFileSize = PEInfo.NewSection.PointerToRawData + PEInfo.NewSection.SizeOfRawData ; TempStr.SetAt ( TempStr.GetLength()-4, 0 ) ; wsprintf ( pBuf, TEXT("%s%s"), TempStr.GetBuffer(TempStr.GetLength()), TEXT("_nag.exe") ) ; if ( PEInfo.CreateNewMap ( pBuf, &NewMap, dwNewFileSize ) == FALSE ) { MessageBox ( TEXT("Could't create new file!") ) ; DeleteFile ( pBuf ) ; return ; } // 添加区块信息 PEInfo.AddNewSection ( &OldMap, &NewMap, dwNewFileSize ) ; // 删除原PE文件的映射 PEInfo.DeleteMap ( &OldMap ) ; // 把pData中的数据写入到新区块( contain IID, NewDllName, NewFunName, NewIat) LPVOID lpNewSection = LPVOID(DWORD(NewMap.lpMapAddr)+PEInfo.NewSection.PointerToRawData) ; memcpy ( lpNewSection, pData, PEInfo.NewSection.SizeOfRawData ) ; // 取得PE头信息 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(NewMap.lpMapAddr) ; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((LONG)(NewMap.lpMapAddr)+ (pDosHeader->e_lfanew)) ; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader) ; // 写入新IID信息 IMAGE_IMPORT_DESCRIPTOR // 如果OriginalFirstThunk 字段的值为0,加载就不会改写IAT,也就是说,需要自己向IAT写入对应函数的地址 // 这里把OriginalFirstThunk的值设置为与FirstThunk相同,这样初始化的时候加载器就会改写IAT PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)lpNewSection + 0x14 * dwIIDNum) ; pIID->Name = dwDllNameOff + PEInfo.NewSection.VirtualAddress ; pIID->FirstThunk = dwIATOff + PEInfo.NewSection.VirtualAddress ; pIID->OriginalFirstThunk = pIID->FirstThunk ; pIID->ForwarderChain = 0xFFFFFFFF ; pIID->TimeDateStamp = 0xFFFFFFFF ; *((DWORD*)(dwIATOff + (DWORD)lpNewSection)) = dwFunNameOff + PEInfo.NewSection.VirtualAddress ; // 修改数据目录项中输入表项信息 pOptionalHeader->DataDirectory[1].VirtualAddress = PEInfo.NewSection.VirtualAddress ; pOptionalHeader->DataDirectory[1].Size += 0x14 ; // 清楚绑定输入表 pOptionalHeader->DataDirectory[11].VirtualAddress = 0 ; pOptionalHeader->DataDirectory[11].Size = 0 ; // 修改OEP pOptionalHeader->AddressOfEntryPoint = dwNewEntryOff + PEInfo.NewSection.VirtualAddress ; PEInfo.FlushData ( LPVOID(PEInfo.NewSection.VirtualAddress), PEInfo.NewSection.SizeOfRawData ) ; PEInfo.DeleteMap ( &NewMap ) ; MessageBox ( TEXT("添加Nag窗口成功!") ) ; } //生成新区块数据 DWORD CNagGenDlg::GenerateData(PBYTE pData, LPVOID lpImageBase) { // 取得PE文件基本信息 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)(lpImageBase) ; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((LONG)(lpImageBase)+ (pDosHeader->e_lfanew)) ; PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNtHeader->OptionalHeader) ; PIMAGE_DATA_DIRECTORY pImportData = (PIMAGE_DATA_DIRECTORY)(&( pOptionalHeader->DataDirectory[1]) ) ; // //定位到导入表 //IMAGE_IMPORT_DESCRIPTOR *pImportDesc=(IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)lpBase+ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); PIMAGE_IMPORT_DESCRIPTOR pIID = (PIMAGE_IMPORT_DESCRIPTOR) ImageRvaToVa ( pNtHeader, lpImageBase, pImportData->VirtualAddress, NULL ) ; // 把原IID表拷贝到缓冲区 memcpy ( pData, LPVOID(pIID), pOptionalHeader->DataDirectory[1].Size );//ImportTable //统计IID数量(dll的数量) dwIIDNum = 0 ; while ( pIID[dwIIDNum].FirstThunk ) dwIIDNum ++ ; char szDllName[] = "USER32.dll" ; char szFunName[] = "MessageBoxA" ; // 设置偏移信息 dwDllNameOff = pOptionalHeader->DataDirectory[1].Size + 0x14; dwFunNameOff = dwDllNameOff + sizeof (szDllName) + 3 ; dwIATOff = dwFunNameOff + sizeof (szFunName) + 4 ; dwNagTitleOff = dwIATOff + 12 ; // 写入DLL名 memcpy ( &(pData[dwDllNameOff]), szDllName, sizeof(szDllName) ) ; // 写入函数名 memcpy ( &(pData[dwFunNameOff+2]), szFunName, sizeof(szFunName) ) ; // 2, 序号 CHAR pTitle[128] = {0}, pContent[512] = {0} ; ::GetDlgItemTextA ( GetSafeHwnd(), IDC_NAG_TITLE, pTitle, 128 ) ; ::GetDlgItemTextA ( GetSafeHwnd(), IDC_NAG_CONTENT, pContent, 512 ) ; // 设置偏移信息(NagTitle + NagContent) dwNagContentOff = dwNagTitleOff + strlen(pTitle) + 1 ; dwNewEntryOff = dwNagContentOff + strlen(pContent) + 1 ; // 把NagTitle和NagContent信息写入缓冲区 wsprintf ( PTCHAR(&pData[dwNagTitleOff]), TEXT("%s"), pTitle ) ; wsprintf ( PTCHAR(&pData[dwNagContentOff]), TEXT("%s"), pContent ) ; // // Stub Code ( 0x11111111为数据占位符,需修正) 0x6a,push 命令, 0xe8,cal命令 // pushad 60 // push 0 6A 0x00 // push 0x11111111 68 11111111 // push 0x11111111 68 11111111 // push 0 6A 00 // call dword ptr MessageBoxW FF15 11111111 // popad 61 // jmp 0x11111111 E9 11111111 ///// //Stub数据 BYTE pbCommand[] = { 0x60, 0x6A, 0x00, 0x68, 0x11, 0x11, 0x11, 0x11, \ 0x68, 0x11, 0x11, 0x11, 0x11, 0x6A, 0x00, 0xFF, 0x15, 0xBC, 0xF2, 0x42, 0x00, 0x61, \ 0xE9, 0x11, 0x11, 0x11, 0x11 } ; // 统计Stub Code长度,然后写入pData缓冲区 DWORD dwStubLength = sizeof(pbCommand); memcpy ( &(pData[dwNewEntryOff]), pbCommand, dwStubLength ) ; // 计算 JMP 指令的操作数 DWORD dwOldEntryRVA = pOptionalHeader->AddressOfEntryPoint ; DWORD dwNewEntryRVA = PEInfo.NewSection.VirtualAddress + dwNewEntryOff + 22 ; DWORD dwJmpDist = dwOldEntryRVA - dwNewEntryRVA - 5 ; // 修正TitleVA *((DWORD*)(&(pData[dwNewEntryOff+4]))) = pOptionalHeader->ImageBase + PEInfo.NewSection.VirtualAddress + dwNagTitleOff ; // 修正ContentVA *((DWORD*)(&(pData[dwNewEntryOff+9]))) = pOptionalHeader->ImageBase + PEInfo.NewSection.VirtualAddress + dwNagContentOff ; // 修正 CALL [0x********] *((DWORD*)(&(pData[dwNewEntryOff+17]))) = pOptionalHeader->ImageBase + PEInfo.NewSection.VirtualAddress + dwIATOff ; // 修正 JMP 的操作数 ==> E9 ** ** ** ** *((DWORD*)(&(pData[dwNewEntryOff+23]))) = dwJmpDist ; // 返回总长度 return dwNewEntryOff + dwStubLength + 0x10 ; }
CString m_NagContent;
afx_msg void OnBnClickedOk();
DWORD GenerateData(PBYTE pData, LPVOID lpImageBase);
};