消息钩子

Windows操作系统GUI将键盘敲击,鼠标移动和点击,窗口大小和位置改变都看成事件(Event).消息传递过程大致为

  • 事件发生时,首先将这个事件添加到系统的[OS message queue]中
  • OS判断这个事件是在哪个应用程序中产生的,然后将这个事件添加到应用程序的消息队列中
  • 应用程序对这些消息进行处理

消息钩子就在这个传递链过程中添加一些函数,这些函数可以侦听事件甚至修改事件的参数。

SetWindowsHookEx

这个API可以实现消息钩子,它的定义如下

HHOOK SetWindowsHookEx
{
int idHoook;
HOOKPROC lpfn;
HINSTANCE hMod;//这个程序所属DLL句柄
DOWRD dwThreadId;//想要挂钩的线程Id
}

DLL注入

DLL注入指的是想运行中的进程强制插入DLL文件。具体来讲就是让其他进程调用LoadLibrary().

具体方法

  • 创建远程线程
  • 使用注册表
  • 消息勾取

创建远程线程

bool inject_dll(DWORD dwPID, LPCTSTR szDllPath)
{
HANDLE hProcess = NULL, hThread = NULL;
HMODULE hMod = NULL;
LPVOID pRemoteBuf = NULL;
DWORD dwBufSize = (DWORD)(_tcslen(szDllPath) + 1) * sizeof(TCHAR);
LPTHREAD_START_ROUTINE pThreadProc;
//获取notepade.exe句柄
if(!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPID)))
{
__tprintf(L"OpenProcess(&d) failed!!!", dwPID, GetLastError());
return false;
}
//在notepad.exe中分配内存
pRemoteBuf = VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
//将myhack.dll写入内存
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllPath, dwBufSize, NULL);
//获取LoadLibraryW()的地址
hMod = GetModuleHandle(L"kernel32.dll");
pThreadProc = (LPTHREAD_START_ROUTINE)GetProcAddress(hMod, "LoadLibraryW");
//在notepad.exe中运行线程
hThread = CreateRemoteThread(hProcess, NULL, 0, pThreadProc, pRemoteBuf, 0, NULL);

WaitForSingleObject(hTread, INFIINITE);
CloseHandle(hTread);
CloseHandle(hProcess);
return true;
}

int main(int argc, char *argv[])
{
if(argc != 3)
{
_tprintf(L"USAGE : %S PID dll_path\n", argv[0]);
return 1;
}

if(InjectDll((DWORD)_TSTOL(argv[1]), argv[2]))
{
_tprintf(L"InjectDll(\""%s\") success!!!\n", argv[2]);
else
{
_tprintf(L"InjectDll(\"%s\") failed!!!\n", argv[2]);
}
return 0;
}
  • OpenProcess(PROCESS_ALL_ACCESS, false, dwPID): 获得目标进程句柄.第一个参数是获得所有权限,最后一个是程序运行时传过来的
  • VirtualAllocEx, WriteProcessMemory: 将dll写入进程
  • GetModuleHandle, GetProceAddress: 获得LoadLibraryW()API的地址
  • CreateRemoteThread: 远程运行线程

使用注册表

Windows操作系统中默认提供AppInit_DLLs和LoadAppInit_DLLs两个注册表项

大致过程为将要注入的DLL的路径字符串吸入AppInit_DLLs项目,然后把LoadAppInit_DLLs项目值设为1.

#define DEF_CMD L"c:\\Program Files\\Internet Explorer\\iexplore.exe"
#define DEF_ADDR L"http://www.naver.com"
#define DEF_DST_PROC L"notepad.exe"

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReaseved)
{
TCHAR szCmd[MAX_PATH] = {0, };
TCHAR szPath[MAX_PATH] = {0, };
TCHAR *p = NULL;
STARTUPINFO si = {0,};

si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_SUESHOWWINDOW;
si.wShowWindow = SW_HIDE;

switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
if(!GetModuleFileName(NULL, szPath, MAX_PATH))
{
break;
}

if(!(p == _tcsrchr(szPath, '\\')))
{
break;
}

if(_tcsicmp(p+1, DEF_DST_PROC))
{
break;
}

wsprintf(szCmd, L"%s %s", DEF_CMD, DEF_ADDR);
if(!CreateProcess(NULL, (LPTSTR)(LPCTSTR)szCmd, NULL, NULL, false, NORMAL_PRIOPRITY_CLASS, NULL, NULL, &si, &pi))
{
break;
}

if(pi.hProcess != NULL)
{
CloseHandle(pi.hProcess);
}
break;
}
return true;
}

这段代码的作用是判断当前加载进程是否是notepad.exe,如果是就运行IE链接网址

接下来要做的就是将DLL信息写进注册表项中。

DLL卸载

DLL卸载就是要让进程调用FreeLibrary()API。

  • CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID): 这个函数的作用是获得加载到进程的DLL信息。返回值是一个句柄,传递给Module32First(返回值, &information)后,就可以在information中获得dll相关信息
    typedef struct tagMODULEENTRY32
    {
    DWORD dwSize;
    DWORD th32ModuleID;
    DWORD th32ProcessID;
    DWORD GlblcntUsage;
    DWORD ProccntUsage;
    BYTE *modBaseAddr;
    DWORD modBaseSize;
    HMODULE hModule;
    char szModule[MAX_MODULE_NAME32 + 1];
    CHAR szExePath[MAX_PATH];
    }MODULEENTRY32;
    上面就是information结构体的具体内容。szModule是这个dll的名称
  • OpenProcess(PROCESS_ALL_ACCESS, FLASE, dwPID): 获得目标进程的句柄
  • GetModuleHandle(“kernel32.dll”)
  • (LPTHREAD_START_ROUNTINE)GetProcAddress(hModule, “FreeLibrary”):上面两个是获取FreeeLibrary的地址
  • CreateRemoteThread(hProcess, NULL, 0, pThreadProc, information.modBaseAddr, 0, NULL): hThreadProc是FreeLibrary的API地址, modBaseAddr是需要卸载的API地址