先说说DLL引用的方法:
如果有lib+dll+头文件
则:建工程的时候选择导出符号
#pragma comment(lib, “libname.lib”)
#include “libname.h”
func();
只有DLL文件
LoadLibrary
GetProcAddress
因为在C++中有函数重整,(函数名会被自动改变),我们需要在DLL中,在函数前加上
extern "C"
声明是C函数,不要重整函数
SetWindowsHookEx 全局钩子
HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \\钩子类型
__in HOOKPROC lpfn, \\回调函数地址
__in HINSTANCE hMod, \\包含lpfn的实例句柄
__in DWORD dwThreadId); \\线程ID,如果为0,则监控所有线程的全局钩子
WH_CALLWNDPROC and WH_CALLWNDPROCRET
WH_CBT
WH_DEBUG
WH_FOREGROUNDIDLE
WH_GETMESSAGE
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD_LL
WH_KEYBOARD
WH_MOUSE_LL
WH_MOUSE
WH_MSGFILTER and WH_SYSMSGFILTER
WH_SHELL
得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。
更多钩子https://msdn.microsoft.com/en-us/library/ms644959(VS.85).aspx
全局钩子:
实现文件如下。其中g_hWnd为所有进程共享,并且绕过了系统对可写数据的写时复制机制,维护的是一份拷贝
// Hook.cpp
#include <windows.h>
HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;
// 为Hook.DLL创建一个新的节,将全局变量g_hWnd放入其中
#pragma data_seg("MySec")
HWND g_hWnd = NULL;
#pragma data_seg()
// 设置刚创建的节为共享的节
#pragma comment(linker, "/section:MySec,RWS")
// 鼠标钩子过程
LRESULT CALLBACK MouseProc(
int nCode, // hook code
WPARAM wParam, // message identifier
LPARAM lParam // mouse coordinates
)
{
return 1; // 屏蔽所有鼠标消息
}
// 键盘钩子过程
LRESULT CALLBACK KeyboardProc(
int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
)
{
// 后门按键用于结束该进程
if (VK_F2 == wParam)
{
::SendMessage(g_hWnd, WM_CLOSE, 0, 0);
UnhookWindowsHookEx(g_hKeyboard);
UnhookWindowsHookEx(g_hMouse);
}
else
{
return 1; // 屏蔽所有键盘消息
}
}
// 安装鼠标钩子过程的函数
void SetHook(HWND hwnd) // 参数是为了让dll获得调用进程的主窗口的句柄
{
g_hWnd = hwnd;
// hook所有进程的鼠标、键盘消息
g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, GetModuleHandle("Hook.dll"), 0);
g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle("Hook.dll"), 0);
}
调用DLL的进程的实现:
/
// CHookTestDlg message handlers
// 导入函数
__declspec(dllimport) void SetHook(HWND hwnd);
BOOL CHookTestDlg::OnInitDialog()
{
// TODO: Add extra initialization here
// 顶层窗口及最大化窗口的实现
int cxScreen, cyScreen;
cxScreen = GetSystemMetrics(SM_CXSCREEN);
cyScreen = GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost, 0, 0, cxScreen, cyScreen, SWP_SHOWWINDOW);
// 调用DLL中的函数
SetHook(m_hWnd);
return TRUE; // return TRUE unless you set the focus to a control
}
资料来自:http://blog.csdn.net/xiaobaohe/article/details/6313814
上面是WH_KEYBOARD
下面是使用WH_KEYBOARD_LL 低级键盘钩子 不需要DLL 直接设置即可
// keyboardhook.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include<windows.h>
using namespace std;
HHOOK g_Hook;
LRESULT CALLBACK LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *)lParam;
BOOL bControlKeyDown = 0;
switch (nCode)
{
case HC_ACTION:
{
// Check to see if the CTRL key is pressed
bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);
//Disable CTRL+ESC
if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown)
return 1;
if(wParam == WM_KEYUP)
printf("%c", pkbhs->vkCode);
break;
}
}
return CallNextHookEx(g_Hook, nCode, wParam, lParam); //回调
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg;
g_Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL,
(HOOKPROC)LowLevelKeyboardProc, GetModuleHandleW(0),0);
while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
return 0;
}
低级鼠标钩子实例:
// mousehook.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include<windows.h>
using namespace std;
/* LPARAM type
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT;
*/
LRESULT CALLBACK LowLevelMouseProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
if(nCode==HC_ACTION)
{
if(wParam==WM_LBUTTONDOWN)
{
return 1;
}
}
return CallNextHookEx(0,nCode,wParam,lParam);
}
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg;
SetWindowsHookExW(WH_MOUSE_LL,LowLevelMouseProc,GetModuleHandleW(0),0);
while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
return 0;
}
QQ安全密码框的全局钩子
1,WH_DEBUG , WH_KEYBOARD_LL, WH_MOUSE_LL
2, WH_DEBUG> WH_KEYBOARD_LL> WH_KEYBOARD
3,后加载的先获得消息并执行
4,QQ定时UNHOOK和HOOK上面3个钩子,保证自己最后被安装,自然就是先取得正确的按键信息,然后阻止这个 消息继续传递下来给别人,就算传下去交给别人,也要修改按键信息,传一个错误的下去
-----------------------------------------------------------------------------------------------------------------------------------------
在下钩子的时候可能我们需要用到通信 可以使用映射,管道,
其实还有一种方便的,就是PE共享节
放到共享节里面的变量时是同实例可以访问的 一般用到多开通信 多开检测,全局dll钩子
#pragma data_seg (".shared")
ULONG g_ulNum;
#pragma data_seg ()
#pragma comment(linker,"/SECTION:.shared,RWS")
RWS:读/写/共享
共享段里的变量可供进程的多个实例访问
普通的全局变量,只对一个实例有效
也可以实现进程通信
将里面的变量extern 在将所在的头文件引用进来 也可以实现通信
详见
hookSpy InjectEx SetWindowHook
LibSpy CreateRemoteThread LoadLibrary
WinSpy CreateRemoteThread WriteProcessMemory
详见:http://blog.csdn.net/danny_share/article/details/38480141
------------------------------------------------------------------------------------------------------------------------------------------------
DLL注入
分为两种:
1.直接把dll注入目标进程
2.直接把代码注入目标进程
直接注入DLL:
AddDebugPrivilege(void)
OpenProcess()
VirtualAllocEx()
WriteProcessMemory()
CreateRemoteThread()
直接注入代码:
static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
…..
…..
}
AddDebugPrivilege(void)
OpenProcess()
VirtualAllocEx()
WriteProcessMemory()
CreateRemoteThread();
Debug权限与进程打开
BOOL AddDebugPrivilege(void)
{
TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE hToken;
if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
{
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid=luid;
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,&hToken))
{
return FALSE;
}
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{
return FALSE;
}
return TRUE;
}
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
PROCESS_VM_READ,FALSE, PID);
其实并不需要这么多函数 但一下函数只能使用在发布版中
typedef long (*RTLADJUSTPRIVILEGE)(ULONG,ULONG,ULONG,PVOID);
RTLADJUSTPRIVILEGE RtlAdjustPrivilege;
RtlAdjustPrivilege=(RTLADJUSTPRIVILEGE)GetProcAddress(LoadLibraryW(L"ntdll.dll"),"RtlAdjustPrivilege");
RtlAdjustPrivilege(20,1,0,&dwRetVal);//debug
RtlAdjustPrivilege(19,1,0,&dwRetVal);
这样就可以了
直接注入DLL文件
1。打开目标进程
2。获取待注入的DLL路径,分配一块目标进程内的内存,将路径拷贝到该内存中
3。获取kernel32中的LoadLibraryA地址
4。调用CreateRemoteThread,在目标进程中执行loadlibrary + DLL的动作
5。DLL中的DLLMAIN执行
6。释放分配的目标进程中的内存
7。获取kernel32中的FreeLibrary地址
8。调用CreateRemoteThread,在目标进程中执行FreeLibrary + DLL的动作
int InjectDll( HANDLE hProcess, TCHAR* szLibPath)
{
<span style="white-space:pre"> </span>HANDLE hThread;
<span style="white-space:pre"> </span>void* pLibRemote = 0;
<span style="white-space:pre"> </span>DWORD hLibModule = 0;
<span style="white-space:pre"> </span>HMODULE hKernel32 = ::GetModuleHandle(_T("Kernel32"));
<span style="white-space:pre"> </span>LPTHREAD_START_ROUTINE pLoadFunc = NULL;
<span style="white-space:pre"> </span>pLoadFunc = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryW");
<span style="white-space:pre"> </span>if (szLibPath == NULL ||
<span style="white-space:pre"> </span>hProcess == NULL ||
<span style="white-space:pre"> </span>pLoadFunc == NULL)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>return FALSE;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>pLibRemote = ::VirtualAllocEx( hProcess, NULL, (_tcslen(szLibPath) + 1)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );
<span style="white-space:pre"> </span>if( pLibRemote == NULL )
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,(_tcslen(szLibPath) + 1)*sizeof(TCHAR),NULL);
<span style="white-space:pre"> </span>hThread = ::CreateRemoteThread( hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pLoadFunc,
<span style="white-space:pre"> </span>pLibRemote, 0, NULL );
<span style="white-space:pre"> </span>if( hThread == NULL )
<span style="white-space:pre"> </span>goto JUMP;
<span style="white-space:pre"> </span>DWORD dwError = GetLastError();
<span style="white-space:pre"> </span>::WaitForSingleObject( hThread, INFINITE );
<span style="white-space:pre"> </span>dwError = GetLastError();
<span style="white-space:pre"> </span>::GetExitCodeThread( hThread, &hLibModule );
<span style="white-space:pre"> </span>::CloseHandle( hThread );
JUMP:<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
<span style="white-space:pre"> </span>if( hLibModule == NULL )
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>return hLibModule;
}
我改进了下 直接使用PID ,虽然方便了点,但我自己也不推荐使用
//向目标进程写入DLL名称,和LoadLibraryW / A 然后通过CreateRemoteThread 远程CALL和传参
int InjectDll( DWORD PID, TCHAR* szLibPath)
{
HANDLE hThread;
void* pLibRemote = 0;
DWORD hLibModule = 0;
HMODULE hKernel32 = ::GetModuleHandle(_T("Kernel32"));
LPTHREAD_START_ROUTINE pLoadFunc = NULL;
pLoadFunc = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryW");
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
PROCESS_VM_READ,FALSE, PID);//这个可以拿出去
if (szLibPath == NULL ||
hProcess == NULL ||
pLoadFunc == NULL)
{
return FALSE;
}
pLibRemote = ::VirtualAllocEx( hProcess, NULL, (_tcslen(szLibPath) + 1)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );
if( pLibRemote == NULL )
return false;
::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,(_tcslen(szLibPath) + 1)*sizeof(TCHAR),NULL);
hThread = ::CreateRemoteThread( hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pLoadFunc,
pLibRemote, 0, NULL );
if( hThread == NULL )
goto JUMP;
DWORD dwError = GetLastError();
::WaitForSingleObject( hThread, INFINITE );
dwError = GetLastError();
::GetExitCodeThread( hThread, &hLibModule );
::CloseHandle( hThread );
JUMP:
::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
if( hLibModule == NULL )
return false;
return hLibModule;
}
//注入程序关键代码
UpdateData(TRUE);
InjectDll(m_edit,_T("MyDll.dll"));
DLL普通的而已
直接注入代码:
实现线程函数
static DWORD WINAPI ThreadFunc (PVOID *pData)
{
......some code
}
static void AfterThreadFunc (void)
{
}
打开目标进程(debug权限)
在目标进程内分配pCodeRemote和pDataRemote并将内容拷贝进去//一个是代码 一个是参数
CreateRemoteThread()启动线程执行
从pDataRemote中拿到结果数据
释放pDataRemote和pCodeRemote
声明AfterTheadFunc的原因是获取ThreadFunc函数的长度
代码:向目标写入函数code,和参数
void InjCode (HANDLE hProcess)
{
INJDATA *pDataRemote;
DWORD *pCodeRemote;
HANDLE hThread = NULL;
DWORD dwThreadId = 0;
DWORD dwNumBytesXferred = 0;
pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT,
PAGE_READWRITE );
WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );
const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc);
pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT,
PAGE_EXECUTE_READWRITE );
WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote, 0 , &dwThreadId);
WaitForSingleObject(hThread, INFINITE);
ReadProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred);
//需要判断pDataRemote,pCodeRemote,hThread的有效性
VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );
VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE );
CloseHandle(hThread);
}
例子:WinSpy
#include <Windows.h>
#include "InjCode.h"
//---------------------------------------------------------------------
// INJDATA
// Notice: The data structure being injected.
//
typedef LRESULT (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM);
typedef struct {
HWND hwnd;
SENDMESSAGE fnSendMessage; // pointer to user32!SendMessage
BYTE pbText[128 * sizeof(TCHAR)];
} INJDATA, *PINJDATA;
//---------------------------------------------------------------------
// ThreadFunc
// Notice: - the code being injected;
// - the remote copy of this function retrieves the password;
//
// Return value: password length
//
static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
// There must be less than a page-worth of local
// variables used in this function.
int nXferred = 0; // number of chars retrieved by WM_GETTEXT
// Get password
nXferred = pData->fnSendMessage( pData->hwnd, WM_GETTEXT,
sizeof(pData->pbText)/sizeof(TCHAR),
(LPARAM)pData->pbText );
pData->pbText [127 * sizeof(TCHAR)] = __TEXT('\0');
// The thread's exit code is the number
// of characters retrieved by WM_GETTEXT
return nXferred;
}
// This function marks the memory address after ThreadFunc.
// int cbCodeSize = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc.
static void AfterThreadFunc (void) {
}
//---------------------------------------------------------------------
// GetTextRemote
// Notice: - copies ThreadFunc and INJDATA to the remote process;
// - starts the excecution of the remote ThreadFunc;
//
// Return value: password length;
//
int GetTextRemote (HANDLE hProcess, HWND hWnd, BYTE* pbString, bool fUnicode)
{
HINSTANCE hUser32;
INJDATA *pDataRemote; // the address (in the remote process) where INJDATA will be copied to;
DWORD *pCodeRemote; // the address (in the remote process) where ThreadFunc will be copied to;
HANDLE hThread = NULL; // the handle to the thread executing the remote copy of ThreadFunc;
DWORD dwThreadId = 0;
int nCharsXferred = 0; // number of chars retrieved by WM_GETTEXT in the remote thread;
DWORD dwNumBytesXferred = 0; // number of bytes written/read to/from the remote process;
__try {
hUser32 = GetModuleHandle(__TEXT("user32"));
if (hUser32 == NULL)
__leave;
// Initialize INJDATA and then
// copy it to the remote process
INJDATA DataLocal = {
hWnd,
(SENDMESSAGE) GetProcAddress(hUser32, fUnicode ? "SendMessageW" : "SendMessageA")
};
if( DataLocal.fnSendMessage == NULL )
__leave;
// 1. Allocate memory in the remote process for INJDATA
// 2. Write a copy of DataLocal to the allocated memory
pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE );
if (pDataRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );
// Calculate the number of bytes that ThreadFunc occupies
const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc);
// 1. Allocate memory in the remote process for the injected ThreadFunc
// 2. Write a copy of ThreadFunc to the allocated memory
pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if (pCodeRemote == NULL)
__leave;
WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
// Start execution of remote ThreadFunc
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote, 0 , &dwThreadId);
if (hThread == NULL)
__leave;
WaitForSingleObject(hThread, INFINITE);
// Get result (password) back
ReadProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred);
if (fUnicode) wcscpy((LPWSTR) pbString, (LPCWSTR) DataLocal.pbText);
else strcpy((LPSTR) pbString, (LPCSTR) DataLocal.pbText);
}
__finally {
if ( pDataRemote != 0 )
VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );
if ( pCodeRemote != 0 )
VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE );
if ( hThread != NULL ) {
GetExitCodeThread(hThread, (PDWORD) &nCharsXferred);
CloseHandle(hThread);
}
}
// Return the number of chars retrieved
// by WM_GETTEXT in the remote thread.
return nCharsXferred;
}
///
int GetWindowTextRemoteA (HANDLE hProcess, HWND hWnd, LPSTR lpString)
{
return GetTextRemote (hProcess, hWnd, (BYTE*)lpString, false);
}
int GetWindowTextRemoteW (HANDLE hProcess, HWND hWnd, LPWSTR lpString)
{
return GetTextRemote (hProcess, hWnd, (BYTE*)lpString, true);
}
End Of File //
获取数据就用ReadProcessMemory
备忘:
hookSpy InjectEx SetWindowHook
LibSpy CreateRemoteThread LoadLibrary
WinSpy CreateRemoteThread WriteProcessMemory