自学内容网 自学内容网

《Windows PE》6.4.2 远程注入DLL

实验四十七:远程注入DLL

写一个窗口程序,将一个dll通过远程注入的方法,注入到第三章的示例程序PEHeader.exe中,支持32位和64位PE。

       ●dll.c

/*------------------------------------------------------------------------
 FileName:dll.c
 实验47:远程注入(DLL)
 (c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <Windows.h>

//入口和退出点
int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
MessageBox(NULL, L"Welcome to PE!", L"Hello", MB_OK);
break;
}
case DLL_THREAD_ATTACH:
break;

case DLL_THREAD_DETACH:
break;

case DLL_PROCESS_DETACH:
break;
}
return TRUE;  
}

resource.h(略)

remoteThread.rc(略)

●remoteThread.c

/*------------------------------------------------------------------------
 FileName:remoteThread.c
 实验46:远程线程注入演示程序
 功能:目标是在进程PEHeader.exe中远程注入一个DLL,运行并显示"Welcome to PE!"对话框。
 测试步骤:当PEHeader.exe运行时,运行remoteThread.exe,文件菜单---插入到PEHeader.exe
 (c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <windows.h>
#include <strsafe.h>//StringCchCopy
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
#include <Richedit.h>
#include <tchar.h>
#include <string.h>
#include "resource.h"

//使用typedef给函数指针类型一个别名,函数指针存储函数地址
typedef FARPROC(__stdcall *_ApiSuspend)(HANDLE);
typedef HMODULE(__stdcall *_ApiResume)(HANDLE);
_ApiSuspend _suspendProcess;
_ApiResume _resumeProcess;

BOOL CALLBACK ProcDlgMain(HWND, UINT, WPARAM, LPARAM);
BOOL _patchPEInfo();
void _Init();
void ShowErrMsg();

HANDLE hInstance;
HWND hWinMain, hWinEdit;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
const TCHARszDllEdit[] = TEXT("RichEd20.dll");
const TCHARszClassEdit[] = TEXT("RichEdit20W");//peinfo.rc中定义
const TCHARszNtdll[] = TEXT("ntdll.dll");
const CHARszSuspend[] = "ZwSuspendProcess";//函数名需要定义为ASCII字符
const CHARszResume[] = "ZwResumeProcess";
const TCHARszErr3[] = TEXT("Error happend when getting address.");
HMODULE hRichEdit, hNtdll;

hRichEdit = LoadLibrary((LPCWSTR)&szDllEdit);
hNtdll = LoadLibrary((LPCWSTR)&szNtdll);
_suspendProcess = (_ApiSuspend)GetProcAddress(hNtdll, szSuspend);
if (!_suspendProcess)
MessageBox(NULL, szErr3, NULL, MB_OK);
_resumeProcess = (_ApiResume)GetProcAddress(hNtdll, szResume);
if (!_resumeProcess)
MessageBox(NULL, szErr3, NULL, MB_OK);

hInstance = GetModuleHandle(NULL);
DialogBoxParam(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)ProcDlgMain, (LPARAM)0);
FreeLibrary(hRichEdit);
return 0;
}

BOOL CALLBACK ProcDlgMain(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
switch (wMsg)
{
case WM_CLOSE:
EndDialog(hWnd, 0);
return TRUE;

case WM_INITDIALOG:
hWinMain = hWnd;
_Init();//初始化
return TRUE;

case WM_COMMAND:
switch (wParam)
{
case IDM_EXIT:
EndDialog(hWnd, 0);
return TRUE;

case IDM_OPEN://停止
_patchPEInfo();
return TRUE;
}
}
return FALSE;
}

void _Init()
{
CHARFORMAT stCf;
static TCHAR szClassEdit[] = TEXT("RichEdit20W");//UNICODE版本
//static TCHAR szClassEdit[] = TEXT("RichEdit20A");//ASCII码版本
static TCHAR szFont[] = TEXT("宋体");
//设置编辑控件
hWinEdit = GetDlgItem(hWinMain, IDC_INFO);
SendMessage(hWinEdit, EM_SETTEXTMODE, TM_PLAINTEXT, 0);
RtlZeroMemory(&stCf, sizeof(stCf));
stCf.cbSize = sizeof(stCf);
stCf.yHeight = 9 * 20;
stCf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD;
StringCchCopy((LPTSTR)&stCf.szFaceName, lstrlen(szFont) + 1, (LPCTSTR)&szFont);
SendMessage(hWinEdit, EM_SETCHARFORMAT, 0, (LPARAM)&stCf);
SendMessage(hWinEdit, EM_EXLIMITTEXT, 0, -1);
}

/*
;--------------------
; 将远程线程打到进程PEHeader.exe中
; 测试方法:首先运行PEHeader.exe
; 启动该程序,单击第一个菜单的第一项
; 会发现桌面上弹出"Welcome to PE!"对话框
;--------------------
*/
BOOL _patchPEInfo()
{
HANDLE phwnd, hProcess, hCreate;
DWORD parent, hProcessID;
static TCHAR strTitle[256];
static TCHAR szBuffer[256];
const TCHAR szTitle[] = TEXT("PE文件头中几个关键地址的定位:");
const TCHAR szErr1[] = TEXT("Error happend when openning.");
const TCHAR szErr2[] = TEXT("Error happend when VirtualAllocEx.");

static int dwProcessID, dwThreadID;
PVOID lpLoadLibrary, lpDllName;
static CHAR szMyDllFull[MAX_PATH];//注意:写入内存中的字符都是ANSI字符

const TCHAR szDllKernel[] = TEXT("Kernel32.dll");
const CHAR szLoadLibrary[] = "LoadLibraryA";//注意:写入内存中的字符都是ANSI字符
const CHAR szMyDll[] = "\\DLL.dll";//注意:写入内存中的字符都是ANSI字符

//准备工作:获取dll的全路径文件名、获取LoadLibrary函数地址等
GetCurrentDirectoryA(MAX_PATH, szMyDllFull);//获取应用程序的当前工作目录
strcat_s(szMyDllFull, MAX_PATH, szMyDll);//添加后缀名
int nLen = sizeof(CHAR)*(strlen(szMyDllFull) + 1);

//获取Kernel32.dll句柄,LoadLibrary函数地址
lpLoadLibrary = GetProcAddress(GetModuleHandle(szDllKernel), (LPCSTR)szLoadLibrary);

//通过标题获得进程的handle
parent = 0;//复位标志
phwnd = GetWindow(GetWindow(GetDesktopWindow(), GW_CHILD), GW_HWNDFIRST);
if (!GetParent(phwnd))
parent = 1;

while (phwnd)
{
if (parent)
{
parent = 0;//复位标志
//得到窗口标题文字
GetWindowText(phwnd, strTitle, sizeof(strTitle));
if (!_tcscmp(szTitle, strTitle))
break;
}
//寻找这个窗口的下一个兄弟窗口
phwnd = GetWindow(phwnd, GW_HWNDNEXT);
if (!GetParent(phwnd))
{
if (IsWindowVisible(phwnd))
parent = 1;
}
}
//根据窗口句柄获取进程ID
GetWindowThreadProcessId(phwnd, &hProcessID);

//1.打开本地进程
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, hProcessID);
if (!hProcess)
{
MessageBox(NULL, szErr1, NULL, MB_OK);
return FALSE;
}

//2.分配空间,以页为单位
lpDllName = VirtualAllocEx(hProcess, NULL, nLen, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!lpDllName)
{
MessageBox(NULL, szErr2, NULL, MB_OK);
return FALSE;
}
//3.写入线程代码,注意:写入内存中的字符都是ANSI字符
SIZE_T dwWrite = 0;
if (!WriteProcessMemory(hProcess, lpDllName, szMyDllFull, nLen, &dwWrite))
{
MessageBox(NULL, L"写入内存失败!\n", NULL, MB_OK);
return FALSE;
}

//4.创建一个在另一个进程的虚拟地址空间中运行的线程
hCreate = CreateRemoteThread(hProcess, NULL, 0, lpLoadLibrary, lpDllName, 0, NULL);

//5.等待线程结束返回,释放资源
WaitForSingleObject(hCreate, -1);
CloseHandle(hCreate);
VirtualFreeEx(hProcess, lpDllName, 0, MEM_FREE);
CloseHandle(hProcess);
return TRUE;
}

运行

      

                     图6-5远程注入DLL

  总结

上述示例程序的功能是在进程PEHeader.exe中远程注入一个DLL,运行并显示"Welcome to PE!"对话框。

测试步骤:当PEHeader.exe运行时,运行remoteThread.exe,点击文件菜单”插入到PEHeader.exe”,就可以将DLL远程注入到进程PEHeader.exe中了。

远程注入的步骤:

1.打开本地进程(调用OpenProcess函数)。

2.目标进程分配空间,以页为单位(调用VirtualAllocEx函数)。

3.写入目标进程完整的DLL文件名,(调用WriteProcessMemory函数)。注意:写入内存中的字符都是ANSI字符。

4.创建远程线程(调用CreateRemoteThread函数)。

5.等待线程结束返回,释放资源(调用WaitForSingleObject函数)。

在VS CreateRemoteThread函数调用处下断点,远程注入参数如下所示:

图6-6 远程注入的参数

我们可以使用windbg调试器附加进程PEHeader.exe,查看进程地址0x04dc0000处的数据就是我们已经注入的DLL完整名称。

0:009> db 0x04dc0000

04dc0000  44 3a 5c 63 6f 64 65 5c-77 69 6e 70 65 5c 63 68  D:\code\winpe\ch

04dc0010  30 36 5c 72 65 6d 6f 74-65 54 68 72 65 61 64 5c  06\remoteThread\

04dc0020  44 4c 4c 2e 64 6c 6c 00-00 00 00 00 00 00 00 00  DLL.dll.........

       对比无DLL注入的方法,使用DLL注入的方法不需要对代码和数据进行重定位(由操作系统自动完成),省去了很多不必要的麻烦,因此也是我们常用的方法。


原文地址:https://blog.csdn.net/bcdaren/article/details/143001637

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!