一、使用BCB实现关键代码的调用(我这里为了使dll注入时程序不至于卡主,所以重新创建了一个线程DllThreadTest)
(1)声明全局变量
HWND hWnd;
DWORD pid;
HANDLE hThread;
HANDLE hProcess;
void* pLibNameRemote;
HMODULE hKernel32;
DWORD hLibModule;
(2)Dll注入之前初始化
void DllThreadTest::InitDll()
{
//hWnd = FindWindow(NULL, "DLL注入测试窗口"); // 查找目标进程
hWnd = FindWindow(NULL, "DLL注入测试窗口"); // 查找目标进程
pid;
hThread; //
GetWindowThreadProcessId(hWnd, &pid); //
EnableDebugPriv(); // 获得进程的调试权
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // 打开进程
// 要注入的dll
pLibNameRemote = VirtualAllocEx(hProcess, NULL, PATHNAME_LENGTH, MEM_COMMIT, PAGE_READWRITE);
// 在目标进程的地址空间分配内存
WriteProcessMemory(hProcess, pLibNameRemote, szLibName, PATHNAME_LENGTH, NULL); // 写入dll路径
hKernel32 = GetModuleHandle("Kernel32"); // 获得kernel32.dll的句柄
FARPROC fp = GetProcAddress(hKernel32, "LoadLibraryA"); // 获得loadibrary的便宜地址
hThread = CreateRemoteThread(hProcess, NULL, 0, // 启动远程线程
(LPTHREAD_START_ROUTINE)fp, // --要注入的代码写在dll的DllMain里
pLibNameRemote, 0, NULL); //
WaitForSingleObject(hThread, INFINITE); // 等待线程结束,也就是dllmain结束
DWORD hLibModule;
GetExitCodeThread(hThread, &hLibModule); // 返回注入的dll的句柄
CloseHandle(hThread);
}
(3)DIll注入调用
void DllThreadTest::StartDllThread()
{
InitDll();
HMODULE hPrint = LoadLibrary("D://BCBPJ//BCBPJ//HookTest//vc//DllInjectTest//Debug//DllInjectTest.dll");
PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)GetProcAddress(hPrint, "StartDllThread");
HANDLE hRemoteThread;
if(pfnStartAddr == NULL)
{
ShowMessage("函数调用失败");
return;
}
if((hRemoteThread=CreateRemoteThread(hProcess,NULL,0,pfnStartAddr,pLibNameRemote,0,NULL))==NULL)
{
ShowMessage("创建线程失败!");
return;
}
WaitForSingleObject(hRemoteThread, INFINITE); // 等待线程结束,也就是dllmain结束
DWORD hLibModule1;
GetExitCodeThread(hRemoteThread, &hLibModule1); // 返回注入的dll的句柄
CloseHandle(hRemoteThread);
//FreeLibrary(hPrint);
EndDll();
ShowMessage("aaaaa");
}
(4)DIll注入终止
void DllThreadTest::EndDll()
{
VirtualFreeEx(hProcess, pLibNameRemote, PATHNAME_LENGTH, MEM_RELEASE);
hThread = CreateRemoteThread(hProcess, NULL, 0, // 释放注入的dll
(LPTHREAD_START_ROUTINE)::GetProcAddress(hKernel32, "FreeLibrary"),
(void*)hLibModule, 0, NULL );
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
(5)提高当前执行线程的执行权限
void DllThreadTest::EnableDebugPriv()
{
HANDLE hToken; // 进程访问令牌的句柄
LUID luid; // 用于存储调试权对应的局local unique identifier
TOKEN_PRIVILEGES tkp; // 要设置的权限
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// 获取访问令牌
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid); // 获得调试权的luid
tkp.PrivilegeCount = 1; // 设置调试权
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL); // 使进程拥有调试权
CloseHandle(hToken);
}
(6)远程调用dll里面的其他输出函数停止dll里面的消息循环
void DllThreadTest::StopDllThread()
{
HMODULE hPrint = LoadLibrary("D://BCBPJ//BCBPJ//HookTest//vc//DllInjectTest//Debug//DllInjectTest.dll");
PTHREAD_START_ROUTINE pfnStartAddr=(PTHREAD_START_ROUTINE)GetProcAddress(hPrint, "SetDllThread");
HANDLE hRemoteThread;
if(pfnStartAddr == NULL)
{
ShowMessage("函数调用失败");
return;
}
else
{}
if((hRemoteThread=CreateRemoteThread(hProcess,NULL,0,pfnStartAddr,pLibNameRemote,0,NULL))==NULL)
{
ShowMessage("创建线程失败!");
return;
}
WaitForSingleObject(hRemoteThread, INFINITE); // 等待线程结束,也就是dllmain结束
DWORD hLibModule1;
GetExitCodeThread(hRemoteThread, &hLibModule1); // 返回注入的dll的句柄
CloseHandle(hRemoteThread);
FreeLibrary(hPrint);
}
二、DllInjectTest.dll的实现
(1)DllInjectTest.h的实现
#ifndef DLL_INJECT_TEST
#define DLL_INJECT_TEST
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <process.h>
DWORD WINAPI WindowCallBackProc(LPVOID *param);
static LRESULT CALLBACK DllTestProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam);
// 声明要导出的函数
extern "C" _declspec(dllexport) void SetDllThread();
extern "C" _declspec(dllexport) void StartDllThread();
#endif
(2)DllInjectTest.cpp的实现
#include "DllInjectTest.h"
HANDLE hThread=NULL;
DWORD dwThread=0;
HWND hwnd,btnHwnd;
DWORD pid;
DWORD g_OldButtonProc;
#pragma data_seg("MySec")
BOOL StopThread=false;
#pragma data_seg()
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID pReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//MessageBoxA(NULL,"DLL_PROCESS_ATTACH!","fuck",0);
break;
case DLL_THREAD_ATTACH:
//MessageBoxA(NULL,"我操!","fuck",0);
break;
case DLL_THREAD_DETACH:
//MessageBoxA(NULL,"DLL_THREAD_DETACH!","fuck",0);
break;
case DLL_PROCESS_DETACH:
//MessageBoxA(NULL,"DLL_PROCESS_DETACH!","fuck",0);
break;
}
//MessageBoxA(NULL,"DLL_PROCESS_DETACH!","fuck",0);
//_beginthread(WindowCallBackProc,0,NULL);
return TRUE;
}
// 线程回调函数
DWORD WINAPI WindowCallBackProc(LPVOID *param)
{
MessageBoxA(NULL,"进入进程!","fuck",0);
hwnd=::FindWindow(NULL,"DLL注入测试窗口");
//hwnd=::FindWindow(NULL,"添加好友");
if(hwnd)
{
EnumChildWindows(hwnd,(WNDENUMPROC)EnumChildProc, 0);//列举子窗口
}
while (!StopThread)
{
}
return 0;
}
void SetDllThread()
{
StopThread=true;
}
void StartDllThread()
{
hThread = ::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WindowCallBackProc,NULL,0,&dwThread);
if(hThread)
{
MessageBoxA(NULL,"cao ni ma ge B!","fuck",0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
}
LRESULT CALLBACK DllTestProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
/*
switch(wp)
{
case EN_CHANGE:
MessageBoxA(NULL,"EN_CHANGE!","fuck",0);
break;
}*/
switch(msg)
{
case WM_SETTEXT:
MessageBoxA(NULL,"设置文本!","fuck",0);
::CallWindowProc((WNDPROC)g_OldButtonProc,hwnd, msg, wp, lp);
break;
}
return ::CallWindowProc((WNDPROC)g_OldButtonProc,hwnd, msg, wp, lp);
}
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
WCHAR lpWinTitle[256],lpClassName[256];
::GetWindowTextW(hwndChild,lpWinTitle,256-1); //获得窗口caption
::GetClassNameW(hwndChild,lpClassName,256-1); //获得窗口类名
::SendMessageW(hwndChild,WM_GETTEXT,100,(long)strTest);
if(_wcsicmp(lpClassName,L"TEdit")==0)
{
//修改窗口的执行函数
g_OldButtonProc=::SetWindowLong(hwndChild,GWL_WNDPROC,(LPARAM)(WNDPROC)DllTestProc);
char strTest[100]="这是一个测试程序";
SendMessage(hwndChild,WM_SETTEXT,0,(LPARAM)strTest);
}
/*
if(_wcsicmp(lpClassName,L"")!=0))
EnumChildWindows(hwndChild,(WNDENUMPROC)EnumChildProc, 0);*/
return true;
}
二、问题总结与分析
(1)在Dll的注入初始化时会调用Dll里面的DllMain函数,此时必须有返回值。
(2)针对第一种情况,我在Dll里面新建了一个处理消息循环的可以创建线程的输出函数SetDllThread,这样做是为了可以在Dll里面做各种消息过滤和Hook等应用做准备。
(3)针对第二种情况,当需要停止Dll里面的消息循环时,可以通过远程调用Dll里面的SetDllThread函数,当退出消息循环时就会执行Dll注入终止函数释放数据。