|
本帖最后由 小希啊 于 2023-8-16 02:26 编辑
一.实现效果
启动notepad.exe时能够加载自己编写的dll.
最终效果如图所示
下面逐步讲解并附带源码
二.编写DLL
自行编写DLL,导出一个函数,弹出对话框
[C++] 纯文本查看 复制代码 // MsgDLL66.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
extern "C"
{
__declspec(dllexport) int Msg() ;
}
DWORD WINAPI ThreadShow(LPVOID LpParameter)
{
char szPath[MAX_PATH]={0};
char szBuf[1024]={0};
GetModuleFileName(NULL,szPath,MAX_PATH);
sprintf(szBuf,"DLL 已注入到进程 %s [pid=%d]\n",szPath,GetCurrentProcessId());
//以3种方式显示自己的存在
//1.Msgbox
MessageBox(NULL,szBuf,"DLL Inject",MB_OK);
//2.控制台
printf("%s",szBuf);
//3.调试器
OutputDebugString(szBuf);
return 0;
}
__declspec(dllexport) int Msg()
{
char szPath[MAX_PATH]={0};
char szBuf[1024]={0};
GetModuleFileName(NULL,szPath,MAX_PATH);
sprintf(szBuf,"DLL 已注入到进程 %s [pid=%d]\n",szPath,GetCurrentProcessId());
MessageBoxA(NULL, szBuf, "小星星", MB_OK);
return 0;
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(NULL,0,ThreadShow,NULL,0,NULL);
Msg();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
上面的源码编译后得到dll文件
三.修改PE输入表实现DLL注入
新建一个工程,把上面得到的dll文件放在工程目录下
代码如下,关键地方都做了注释,如果PE基本结构体都不懂,那还是建议先系统学习下,精易逆向安全培训就挺不错,主讲老师根哥真的是我遇到过的线上最好的培训老师,零基础的也不用担心,我就是零基础开始学的.
[C++] 纯文本查看 复制代码 // PEImportDllInject.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#define FilePath "c:\\NOTEPAD.EXE"
#define NewFilePath "c:\\NOTEPAD_new1.EXE"
// 把文件读到Buffer里面
LPVOID FileToBuffer()
{
HANDLE hFile;
DWORD lpFileSizeHigh;
DWORD dwFileSize;
LPVOID FileBuffer;
DWORD lpNumberOfBytesRead;
BOOL bRead;
hFile = CreateFile(FilePath, GENERIC_ALL,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if ( hFile == NULL)
{
printf("CreateFile error %d\n", GetLastError());
}
dwFileSize = GetFileSize(hFile,&lpFileSizeHigh);
if ( dwFileSize == NULL)
{
printf("GetFileSize error %d\n", GetLastError());
}
FileBuffer = VirtualAlloc(0,dwFileSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
if ( FileBuffer == NULL)
{
printf("VirtualAlloc error %d\n", GetLastError());
}
bRead = ReadFile(hFile,FileBuffer,dwFileSize,&lpNumberOfBytesRead,NULL);
if ( bRead == FALSE)
{
printf("ReadFile error %d\n", GetLastError());
}
CloseHandle(hFile);
return FileBuffer;
}
// 从文件拷贝到内存
LPVOID FileToMemory(LPVOID FileBuffer)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeaders;
PIMAGE_FILE_HEADER pImageFileHeader;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
pImageDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageNtHeaders+0x4);
pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pImageFileHeader+sizeof(IMAGE_FILE_HEADER));
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImageFileHeader->SizeOfOptionalHeader);
DWORD dwSizeofImage = pImageOptionalHeader->SizeOfImage;
DWORD dwSizeofHeader = pImageOptionalHeader->SizeOfHeaders;
LPVOID MemoryBuffer;
int i;
MemoryBuffer = VirtualAlloc(0,dwSizeofImage*0x10,MEM_COMMIT,PAGE_READWRITE);
if ( MemoryBuffer == NULL)
{
printf("VirtualAlloc error %d\n", GetLastError());
}
memcpy(MemoryBuffer,FileBuffer,dwSizeofHeader);
for ( i = 0; i < pImageFileHeader->NumberOfSections; i++)
{
memcpy( (BYTE*)((DWORD)MemoryBuffer+ pImageSectionHeader.VirtualAddress),
(BYTE*)((DWORD)FileBuffer+ pImageSectionHeader.PointerToRawData),
pImageSectionHeader.SizeOfRawData);
}
return MemoryBuffer;
}
// 从内存拷贝到新的文件
LPVOID MemoryToNewFile(LPVOID MemoryBuffer)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeaders;
PIMAGE_FILE_HEADER pImageFileHeader;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
pImageDosHeader = (PIMAGE_DOS_HEADER)MemoryBuffer;
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageNtHeaders+0x4);
pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pImageFileHeader+sizeof(IMAGE_FILE_HEADER));
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImageFileHeader->SizeOfOptionalHeader);
DWORD dwSizeofImage = pImageOptionalHeader->SizeOfImage;
DWORD dwSizeofHeader = pImageOptionalHeader->SizeOfHeaders;
LPVOID NewFileBuffer;
int i;
NewFileBuffer = VirtualAlloc(0,dwSizeofImage,MEM_COMMIT,PAGE_READWRITE);
if ( NewFileBuffer == NULL)
{
printf("VirtualAlloc error %d\n", GetLastError());
}
memcpy(NewFileBuffer,MemoryBuffer,dwSizeofHeader);
for ( i = 0; i < pImageFileHeader->NumberOfSections; i++)
{
memcpy( (BYTE*)((DWORD)NewFileBuffer+ pImageSectionHeader.PointerToRawData),
(BYTE*)((DWORD)MemoryBuffer+ pImageSectionHeader.VirtualAddress),
pImageSectionHeader.Misc.VirtualSize);
}
return NewFileBuffer;
}
// 存盘写文件
void WriteToFile(LPVOID NewFileBuffer)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeaders;
PIMAGE_FILE_HEADER pImageFileHeader;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
pImageDosHeader = (PIMAGE_DOS_HEADER)NewFileBuffer;
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageNtHeaders+0x4);
pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pImageFileHeader+sizeof(IMAGE_FILE_HEADER));
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImageFileHeader->SizeOfOptionalHeader);
HANDLE hNewFile;
DWORD dwFileSize;
DWORD lpNumberOfBytesWritten;
BOOL bWrite;
hNewFile = CreateFile(NewFilePath, GENERIC_ALL,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if ( hNewFile == NULL)
{
printf("CreateFile error %d\n", GetLastError());
}
int k = pImageFileHeader->NumberOfSections-1;
dwFileSize = pImageSectionHeader[k].PointerToRawData + pImageSectionHeader[k].SizeOfRawData;
bWrite = WriteFile(hNewFile,NewFileBuffer, dwFileSize,&lpNumberOfBytesWritten,NULL);
if ( bWrite == FALSE)
{
printf("WriteFile error %d\n", GetLastError());
}
CloseHandle(hNewFile);
}
//增加节表
DWORD AddSection(LPVOID MemoryBuffer, char* SectionName, DWORD SectionSize)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeaders;
PIMAGE_FILE_HEADER pImageFileHeader;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
pImageDosHeader = (PIMAGE_DOS_HEADER)MemoryBuffer;
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageNtHeaders+0x4);
pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pImageFileHeader+sizeof(IMAGE_FILE_HEADER));
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImageFileHeader->SizeOfOptionalHeader);
pImageOptionalHeader->DataDirectory[0xb].Size = 0;
pImageOptionalHeader->DataDirectory[0xb].VirtualAddress = 0;
DWORD AddFileAddress;
DWORD AddMemAddress;
int i = pImageFileHeader->NumberOfSections;
pImageFileHeader->NumberOfSections += 0x1;
AddFileAddress = pImageSectionHeader[i-1].PointerToRawData + pImageSectionHeader[i-1].SizeOfRawData;
AddMemAddress = pImageSectionHeader[i-1].VirtualAddress+ pImageSectionHeader[i-1].Misc.VirtualSize;
if ( AddFileAddress % 0x1000 )
{
AddFileAddress = (AddFileAddress+0x1000)&0xFFFFF000;
}
if ( AddMemAddress % 0x1000 )
{
AddMemAddress = (AddMemAddress+0x1000)&0xFFFFF000;
}
strcpy( (char*)pImageSectionHeader.Name, SectionName);
pImageSectionHeader.PointerToRawData = AddFileAddress;
pImageSectionHeader.VirtualAddress = AddMemAddress;
pImageSectionHeader.SizeOfRawData = SectionSize;
pImageSectionHeader.Misc.VirtualSize = SectionSize;
pImageSectionHeader.Characteristics = 0xFFFFFFFF;
pImageOptionalHeader->SizeOfImage = pImageSectionHeader.VirtualAddress+pImageSectionHeader.Misc.VirtualSize;
DWORD AddSectionBuffer;
AddSectionBuffer = (DWORD)MemoryBuffer+AddMemAddress;
return AddSectionBuffer;
}
//输入表dll注入
int DLLInject(LPVOID MemoryBuffer,DWORD AddSectionBuffer)
{
PIMAGE_DOS_HEADER pImageDosHeader;
PIMAGE_NT_HEADERS pImageNtHeaders;
PIMAGE_FILE_HEADER pImageFileHeader;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader;
PIMAGE_SECTION_HEADER pImageSectionHeader;
PIMAGE_IMPORT_DESCRIPTOR pImport;
pImageDosHeader = (PIMAGE_DOS_HEADER)MemoryBuffer;
pImageNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
pImageFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pImageNtHeaders+0x4);
pImageOptionalHeader = (PIMAGE_OPTIONAL_HEADER)((DWORD)pImageFileHeader+sizeof(IMAGE_FILE_HEADER));
pImageSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImageFileHeader->SizeOfOptionalHeader);
pImport=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)MemoryBuffer+pImageOptionalHeader->DataDirectory[1].VirtualAddress);
DWORD TotalSize;
DWORD* NewAddr=(DWORD*)AddSectionBuffer;
//1.备份原IID结构
memcpy(NewAddr,pImport,pImageOptionalHeader->DataDirectory[1].Size);
//结束标记 以0结束
memset((void*)((DWORD)NewAddr+pImageOptionalHeader->DataDirectory[1].Size),0,sizeof(_IMAGE_IMPORT_DESCRIPTOR));
//2.在原IID 区域构造新的IID的OFT Name FT结构
DWORD DLLNameRVA=(DWORD)pImport+0x16;
char*DLLName="MsgDLL66.dll";
DWORD DLLNameSize=(strlen(DLLName)+1+1)&0xe;
memcpy((void*)DLLNameRVA,DLLName,DLLNameSize);
DWORD ByNameRVA=DLLNameRVA+DLLNameSize;
memset((void*)ByNameRVA,0,2);//hint填充为0
char*FunName="Msg";
DWORD FunNameSize=(strlen(FunName)+1+1)&0xe;
memcpy((void*)(ByNameRVA+2),FunName,FunNameSize);
*(DWORD*)pImport=ByNameRVA-(DWORD)MemoryBuffer;
*(DWORD*)((DWORD)pImport+0x4)=0x0;
*(DWORD*)((DWORD)pImport+0x8)=ByNameRVA-(DWORD)MemoryBuffer;
*(DWORD*)((DWORD)pImport+0xc)=0x0;
//3.填充新输入表项的IID结构
PIMAGE_IMPORT_DESCRIPTOR NewIID=(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)NewAddr+pImageOptionalHeader->DataDirectory[1].Size-sizeof(_IMAGE_IMPORT_DESCRIPTOR));
NewIID->OriginalFirstThunk=(DWORD)pImport-(DWORD)MemoryBuffer;
NewIID->Name=DLLNameRVA-(DWORD)MemoryBuffer;
NewIID->FirstThunk=(DWORD)pImport+0x8-(DWORD)MemoryBuffer;
//4.修正PE文件头的信息
//修改.txt属性
pImageSectionHeader[0].Characteristics=0xE0000020;
//修改新节表的属性为0xFFFFFFFF 以及数据目录第B项改为00 (新增节时已经改了)
//更正输入表的地址以及大小
pImageOptionalHeader->DataDirectory[1].VirtualAddress=(DWORD)NewAddr-(DWORD)MemoryBuffer;
pImageOptionalHeader->DataDirectory[1].Size+=sizeof(_IMAGE_IMPORT_DESCRIPTOR);
return 0;
}
int main(int argc, char* argv[])
{
LPVOID FileBuffer;
LPVOID MemoryBuffer;
LPVOID NewFileBuffer;
DWORD AddSectionBuffer;
// 把文件读到Buffer里面
FileBuffer = FileToBuffer();
// 从文件拷贝到内存
MemoryBuffer = FileToMemory(FileBuffer);
//增加节表
AddSectionBuffer = AddSection(MemoryBuffer, ".111", 0x1000);
//DLL注入
DLLInject(MemoryBuffer,AddSectionBuffer);
// 从内存拷贝到新的文件
NewFileBuffer = MemoryToNewFile(MemoryBuffer);
// 存盘写文件
WriteToFile(NewFileBuffer);
printf("Hello World!\n");
return 0;
}
四.测试效果
运行后在C盘生成了如下新文件
双击后在打开记事本之前首先弹出了我们注入的dll弹框
毫无疑问,注入成功
我们再用od加载
可以看到,我们的dll也在其中
用LordPE工具加载在输入表里也看到了我们自己写的dll
由此可见,dll注入确实成功啦
在逆向三期中有一个作业就是自己写一个LordPE工具,跟着老师的课程来,这个作业一点不难,本来想上传视频分享下我写的,发现好像发不了视频,就此作罢
大家如果有任何不明白的地方欢迎与我交流,我必定知无不言,也欢迎大家报名逆向四期!
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|