最简单的 远程线程实现自定义Dll注入
首先做一个Dll,名字叫DllInsert.dll,我们在DllMain中的DLL_PROCESS_ATTACH分支写一个::MessageBox(NULL, "You are Load dll now!", "Load", NULL); 在DLL_PROCESS_DETACH中写一个::MessageBox(NULL, "You are Free dll now!", "Free", NULL); ok Dll写完了,把这个Dll放到System32目录中
下面来注入他到Explorer.exe进程,注意:Debug版本会崩溃,Release版本没问题的,原因不白
#include "Tlhelp32.h."
#include "Psapi.h."
//提升权限
BOOL ImproveProcPriv()
{
HANDLE token;
//提升权限
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token))
{
// MessageBox(NULL,"打开进程令牌失败...","错误",MB_ICONSTOP);
return FALSE;
}
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges.Luid);
tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(token,FALSE,&tkp,sizeof(tkp),NULL,NULL))
{
// MessageBox(NULL,"调整令牌权限失败...","错误",MB_ICONSTOP);
return FALSE;
}
CloseHandle(token);
return TRUE;
}
//这个函数名字取反了,- -! 尴尬
DWORD GetProcNameByPID(char *strName)
{
HANDLE hprocessSnap = NULL;
PROCESSENTRY32 pe32;
memset(&pe32, 0, sizeof(PROCESSENTRY32));
hprocessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//创建进程快照
// 如果创建快照失败就返回1;
if (hprocessSnap == INVALID_HANDLE_VALUE)
{
printf("\nCreateToolhelp32Snapshot()failed:%d",GetLastError());
return 0;
}
pe32.dwSize = sizeof(PROCESSENTRY32); //初始化pe32的dwsize值
//遍历快照
if (Process32First(hprocessSnap,&pe32))
{
do
{
//如果name(要查找的进程的名字)等于pe32.szExeFile(本进程的名字),就返pe32.the32ProcessID (进程ID)
if (!stricmp(strName, pe32.szExeFile))
{
return (DWORD)pe32.th32ProcessID;
}
}while (Process32Next(hprocessSnap,&pe32));
}
//如果没找到就返回0
CloseHandle (hprocessSnap);
return 0;
}
// ========== 定义一个代码结构,本例为一个对话框============
//类似的可以调用Dll里面是函数,只是要把函数名字作为参数传进来
struct MyData
{
char sz; // 对话框显示内容
DWORD dwLoadLibrary; // LoadLibrary的地址
DWORD dwFreeLibrary;
};
// ========== 远程线程的函数 ==============================
DWORD __stdcall RMTFunc(MyData *pData)
{
typedef HMODULE(__stdcall *MLoadLibrary)(LPCTSTR);
typedef void (__stdcall *MFreeLibrary)(HMODULE);
MLoadLibrary Mloaddll = (MLoadLibrary )(pData->dwLoadLibrary);
MFreeLibrary Mfreedll = (MFreeLibrary )(pData->dwFreeLibrary);
HMODULE hDll = Mloaddll(pData->sz);
Mfreedll(hDll);
return 0;
}
void CInsertExplorerDlg::OnOK()
{
ImproveProcPriv();
DWORD dwIDExplorer = GetProcNameByPID("Explorer.exe");
if (dwIDExplorer == 0)
{
::MessageBox(m_hWnd, "Get Pro ID Error!", NULL, NULL);
}
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
FALSE,
dwIDExplorer);
if (hProcess == NULL)
{
::MessageBox(m_hWnd, "Open Process Error!", NULL, NULL);
return ;
}
// ========= 代码结构 ================================================
MyData data;
ZeroMemory(&data, sizeof (MyData));
strcpy(data.sz, "DllInsert.dll");
HINSTANCE hUser = LoadLibrary("kernel32.dll");
if (! hUser)
{
printf("Can not load library.\n");
return ;
}
data.dwLoadLibrary = (DWORD)GetProcAddress(hUser, "LoadLibraryA");
data.dwFreeLibrary = (DWORD)GetProcAddress(hUser, "FreeLibrary");
FreeLibrary(hUser);
if (! data.dwLoadLibrary)
return ;
// ======= 分配空间 ===================================================
void *pRemoteThread
= VirtualAllocEx(hProcess, 0,
1024*4, MEM_COMMIT|MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
if (! pRemoteThread)
return ;
if (! WriteProcessMemory(hProcess, pRemoteThread, &RMTFunc, 1024*4, 0))
return ;
MyData *pData
= (MyData*)VirtualAllocEx(hProcess, 0,
sizeof (MyData), MEM_COMMIT,
PAGE_READWRITE);
if (!pData)
return ;
if (! WriteProcessMemory(hProcess, pData, &data, sizeof (MyData), 0))
return ;
// =========== 创建远程线程 ===========================================
HANDLE hThread
= CreateRemoteThread(hProcess, 0,
0, (LPTHREAD_START_ROUTINE)pRemoteThread,
pData, 0, 0);
if (! hThread)
{
printf("远程线程创建失败");
return ;
}
CloseHandle(hThread);//这个CloseHandle是不会关掉远程线程的,TerminateThread能关掉
VirtualFreeEx(hProcess, pRemoteThread, 1024*4, MEM_RELEASE);
VirtualFreeEx(hProcess, pData, sizeof (MyData), MEM_RELEASE);
CloseHandle(hProcess);
return ;
}
前面说的那个为什么会崩溃,查了一下原因:
原因是Debug模式下编译器会自动在代码中插入esp的check routine.它可以使Remote Thread崩溃.
在DEBUG模式下常有这一句:
0043E604 call @ILT+4380(__RTC_CheckEsp) (42E121h)
CreateRemoteThread中莫名其妙的崩溃常由它导致.由于没有你所有的代码,所以只是推测,没有办法详细了.
一般来说这是由于在Debug模式下,编译会在每个函数执行后自动加入
恢复stockheap地址等相关指令,也就是说,它会调用自动恢复stockheap地址函数。
而这个函数在远程地址空间中是不存在的,所以执行时会出错,
如在Release模式下,编译器就不会插入这个指令,所以执行没有问题。
其实这个问题跟远程执行插入你自己的代码也是一样的,都需要在release下面才能
执行成功。
页:
[1]