//=============================================================================
// 程序: apiHook.c
// 作者: luoluo [[email protected]]
// 参考: 《挂钩Windows API》SOBEIT翻译
// 《通用Shellcode深入剖析》yellow文
// 说明: 通过修改IAT来进行API Hook的例子,没有加载dll,直接跳转到我
// 远程注入的code中去,如果你要写功能复杂的程序,还是写dll方便。
// 环境: windows 2000/xp/2003
//=============================================================================
#include <Windows.h>
#include <Tlhelp32.h>
#include <Imagehlp.h>
#pragma comment(lib, "advapi32.lib")
#define THREADSIZE 1024 * 4
//———–数据结构定义开始————–//
//
// 远程线程函数参数
//
typedef struct _RemotePara
{
//
// 一些函数的地址
//
DWORD dwMessageBox;
DWORD dwGetModuleHandle;
DWORD dwGetProcAddress;
DWORD dwLoadLibrary;
DWORD dwVirtualQuery;
DWORD dwVirtualProtect;
DWORD dwGetWindowText;
DWORD dwZeroMemory;
DWORD dw_stricmp;
char lpLibName[32]; // 要挂钩的模块
char lpHookApiName[32]; // 要挂钩的API函数
char lpImagehlp[32]; // Imagehlp.dll名称
char lpImageDirectoryEntryToData[32]; // 函数名称
char lpKernel32[32]; // Kernel32.dll模块名称
} RemotePara, *PRemotePara;
//———–数据结构定义结束————–//
//———–函数原型定义开始————//
DWORD WINAPI GetProcessIdByName(LPCTSTR lpProcessName);
BOOL WINAPI ThreadInject(DWORD pId);
BOOL WINAPI CreateParameter(PRemotePara pRemotePara);
//———–函数原型定义结束————//
//
// 远程线程函数
//
DWORD WINAPI ThreadProc(PRemotePara lpPara)
{
typedef int (__stdcall *PMessageBox)(HWND, LPCTSTR, LPCTSTR, UINT);
typedef HMODULE (__stdcall *PGetModuleHandle)(LPCTSTR);
typedef FARPROC (__stdcall *PGetProcAddress)(HMODULE, LPCSTR);
typedef HMODULE (__stdcall *PLoadLibrary)(LPCTSTR);
typedef SIZE_T (__stdcall *PVirtualQuery)(LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T);
typedef BOOL (__stdcall *PVirtualProtect)(LPVOID, SIZE_T, DWORD, PDWORD);
typedef PVOID (__stdcall *PImageDirectoryEntryToData)(PVOID, BOOLEAN, USHORT, PULONG);
typedef VOID (__stdcall *PZeroMemory)(LPVOID, SIZE_T);
typedef int (__cdecl *P_stricmp)(const char *, const char *);
PMessageBox pfnMessageBox = (PMessageBox)lpPara->dwMessageBox;
PGetModuleHandle pfnGetModuleHandle = (PGetModuleHandle)lpPara->dwGetModuleHandle;
PGetProcAddress pfnGetProcAddress = (PGetProcAddress)lpPara->dwGetProcAddress;
PLoadLibrary pfnLoadLibrary = (PLoadLibrary)lpPara->dwLoadLibrary;
PVirtualQuery pfnVirtualQuery = (PVirtualQuery)lpPara->dwVirtualQuery;
PVirtualProtect pfnVirtualProtect = (PVirtualProtect)lpPara->dwVirtualProtect;
PZeroMemory pfnZeroMemory = (PZeroMemory)lpPara->dwZeroMemory;
P_stricmp pfn_stricmp = (P_stricmp)lpPara->dw_stricmp;
DWORD pfnHookApiAddr;
PImageDirectoryEntryToData pfnImageDirectoryEntryToData;
DWORD pfnHookAPIAddr;
DWORD pfnMyHookCode;
HMODULE hModule;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
PIMAGE_THUNK_DATA pThunk;
ULONG ulSize;
PSTR pLibName;
MEMORY_BASIC_INFORMATION mbi;
PDWORD pdwfn;
DWORD dwOldProtect;
DWORD dwLibBaseAddr;
//
// 调试代码
//
/*
__asm
{
push ecx
call _lpMsg
_emit ’H’
_emit ’e’
_emit ’l’
_emit ’l’
_emit ’o’
_emit 0×00
_lpMsg:
pop ecx
push 0×00
push ecx
push ecx
push 0×00
call pfnMessageBox
pop ecx
}
*/
__asm
{
push ecx
mov eax, 0×12345678 // 设置是否在本线程的标识
call _next1
_next1:
pop ecx // 取得当前的EIP
add ecx, 0×07 // 跳3个指令
mov pfnMyHookCode, ecx // 挂钩代码地址
_hookCodeStart:
cmp eax, 0×12345678 // 检查标识
jz _hookCodeEnd // 如果在本线程,则跳过挂钩代码
push ebp
mov ebp, esp
sub esp, 0×20 // 开辟局部存储区,存放局部变量
//
// Start
// 这段利用SEH取得kernel32.dll映像基址的程序,拷贝自yellow的《通用shellcode的深入剖析》一文
/////////////////////////////////////////////////////////////////////////////////////////////////////////
push esi
push ecx
mov esi, fs:0
lodsd
GetExeceptionFilter:
cmp [eax], 0xffffffff
je GetedExeceptionFilter // 如果到达最后一个节点(它的pfnHandler指向UnhandledExceptionFilter)
mov eax, [eax] // 否则往后遍历,一直到最后一个节点
jmp GetExeceptionFilter
GetedExeceptionFilter:
mov eax, [eax+4]
FindMZ:
and eax, 0xffff0000 // 根据PE执行文件以64k对界的特征加快查找速度
cmp word ptr [eax], ‘ZM’ // 根据PE可执行文件特征查找KERNEL32.DLL的基址
jne MoveUp // 如果当前地址不符全MZ头部特征,则向上查找
mov ecx, [eax+0x3c]
add ecx, eax
cmp word ptr [ecx], ‘EP’ // 根据PE可执行文件特征查找KERNEL32.DLL的基址
je Found // 如果符合MZ及PE头部特征,则认为已经找到,并通过Eax返回给调用者
MoveUp:
dec eax // 准备指向下一个界起始地址
jmp FindMZ
Found:
mov ecx, eax // 保存Kernel32.dll基址
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// End
//
mov eax, dword ptr [eax + 0x3c] // PE头偏移
add ecx, eax
mov dword ptr [esp + 0x04], ecx // 保存PE头地址
mov ecx, [ecx - 0x05] // 取得MessageBoxA地址
mov byte ptr [ebp - 0x0c], ‘H’
mov byte ptr [ebp - 0x0b], ‘o’
mov byte ptr [ebp - 0x0a], ‘o’
mov byte ptr [ebp - 0x09], ‘k’
mov byte ptr [ebp - 0x08], ‘S’
mov byte ptr [ebp - 0x07], ‘u’
mov byte ptr [ebp - 0x06], ‘c’
mov byte ptr [ebp - 0x05], ‘c’
mov byte ptr [ebp - 0x04], ‘e’
mov byte ptr [ebp - 0x03], ’s’
mov byte ptr [ebp - 0x02], ’s’
mov byte ptr [ebp - 0x01], 0×00
lea eax, [ebp - 0x0c]
push 0 // MB_OK
push eax // "HookSuccess"
push eax // "HookSuccess"
push 0 // NULL
call ecx // 调用MessageBoxA
pop ecx
pop esi
add esp, 0×20 // 恢复堆栈
pop ebp // 恢复堆栈
pop eax // 寄存EIP
add esp, 0×10 // 恢复堆栈
push eax // 压入EIP
mov eax, 0×00 // 设置返回值
ret
_hookCodeEnd:
pop ecx
}
//
// 取得要挂钩的API的地址
//
hModule = pfnGetModuleHandle(lpPara->lpLibName);
pfnHookApiAddr = (DWORD)pfnGetProcAddress(hModule, lpPara->lpHookApiName);
//
// 载入Imagehlp.dll,并取得相关函数地址
//
hModule = pfnLoadLibrary(lpPara->lpImagehlp);
pfnImageDirectoryEntryToData = (PImageDirectoryEntryToData)pfnGetProcAddress(hModule, lpPara->lpImageDirectoryEntryToData);
//
// 取得改进程执行体映象的IAT地址
//
hModule = pfnGetModuleHandle(NULL);
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)pfnImageDirectoryEntryToData(hModule, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
//
// 遍历IMAGE_IMPORT_DESCRIPTOR结构
//
while (pImportDesc->Name)
{
// 取得模块名称
pLibName = (PSTR)((DWORD)hModule + pImportDesc->Name);
// 对比模块名称,如果是要挂钩的API所在的模块则跳出
if (pfn_stricmp(pLibName, lpPara->lpLibName) == 0)
break;
pImportDesc ++;
}
// 取得要挂钩模块的API函数地址数组
pThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + pImportDesc->FirstThunk);
//
// 遍历该数组
//
while (pThunk->u1.Function)
{
// 取得函数地址
pdwfn = (PDWORD)&pThunk->u1.Function;
// 对比函数地址,看是否是要挂钩的API函数地址
if ((*pdwfn) == pfnHookApiAddr)
{
//
// 修改函数入口地址
//
pfnZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
pfnVirtualQuery((LPCVOID)pdwfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
pfnVirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
*pdwfn = pfnMyHookCode;
pfnVirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
//
// 保存MessageBoxA地址到Kernel32的PE头地址 – 5,供Hook Code调用,偶想的笨方法^_^
//
dwLibBaseAddr = (DWORD)pfnGetModuleHandle(lpPara->lpKernel32);
// 取得Kernel32映象PE头地址
dwLibBaseAddr += *(PDWORD)(dwLibBaseAddr + 0×3c);
pfnZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
pfnVirtualQuery((LPCVOID)(dwLibBaseAddr – 5), &mbi, sizeof(MEMORY_BASIC_INFORMATION));
pfnVirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
*(PDWORD)(dwLibBaseAddr – 5) = (DWORD)pfnMessageBox;
pfnVirtualProtect(mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
break;
}
pThunk ++;
}
FreeAndExit:
return 0;
}
//
// Start of WinMain
//
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow)
{
DWORD pId;
OSVERSIONINFOEX osvi;
BOOL bRet;
TCHAR procName[] = TEXT("notepad.exe");
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
//
// Get system version
//
bRet = GetVersionEx((OSVERSIONINFO *)&osvi);
if (! bRet)
{
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bRet = GetVersionEx((OSVERSIONINFO *)&osvi);
if (! bRet)
goto FreeAndExit;
}
// Verify if it is NT system
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
pId = GetProcessIdByName(procName);
if (pId != 0)
ThreadInject(pId);
}
FreeAndExit:
return 0;
}
//
// End of WinMain
//
//
// @Name: GetProcessIdByName
// @Author: luoluo
// @Time: 2005-04-17
// @Param: lpProcessName spacifies the ProcessName
// @Ret: if success, return the process id
// if failed, return 0
//
DWORD WINAPI GetProcessIdByName(LPCTSTR lpProcessName)
{
HANDLE hSnapshot;
DWORD dwRet = 0;
LPPROCESSENTRY32 pPe32;
BOOL bRet;
// Get all the processes in the snapshot
hSnapshot = CreateToolhelp32Snapshot(0×00000002, 0);
if (hSnapshot == INVALID_HANDLE_VALUE)
{
goto FreeAndExit;
}
pPe32 = (LPPROCESSENTRY32)malloc(sizeof(PROCESSENTRY32));
ZeroMemory(pPe32, sizeof(PROCESSENTRY32));
pPe32->dwSize = sizeof(PROCESSENTRY32);
// Get the first process
bRet = Process32First(hSnapshot, pPe32);
if (! bRet)
{
goto FreeAndExit;
}
if (stricmp(lpProcessName, pPe32->szExeFile) == 0)
{
dwRet = pPe32->th32ProcessID;
goto FreeAndExit;
}
// Travesal the left processes
while (TRUE)
{
bRet = Process32Next(hSnapshot, pPe32);
if (! bRet)
{
goto FreeAndExit;
}
if (stricmp(lpProcessName, pPe32->szExeFile) == 0)
{
dwRet = pPe32->th32ProcessID;
goto FreeAndExit;
}
}
FreeAndExit:
if (pPe32 != NULL) free(pPe32);
if (hSnapshot != NULL) CloseHandle(hSnapshot);
return dwRet;
}
//
// @Name: ThreadInject
// @Author: luoluo
// @Time: 2005-04-17
// @Param: pid spacifies the pid of the process to be thread injected
// @Ret: if success return TRUE else return FALSE
//
BOOL WINAPI ThreadInject(DWORD pId)
{
HANDLE hProcess;
LPVOID lpCodeMemory;
BOOL bRet = FALSE;
BOOL bRetVal;
RemotePara myRemotePara;
PRemotePara pRemotePara;
HANDLE hThread;
DWORD dwByteWrite;
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
MEMORY_BASIC_INFORMATION mbi;
SIZE_T szRet;
DWORD dwOldProtect;
// Open process token to ajust privileges
bRetVal = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if (! bRetVal)
{
goto FreeAndExit;
}
// Get the LUID for debug privilege
bRetVal = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
if (! bRetVal)
{
goto FreeAndExit;
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Adjust token privileges
bRetVal = AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(&tkp), (PTOKEN_PRIVILEGES)NULL, 0);
if (! bRetVal)
{
goto FreeAndExit;
}
// Open remote process
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, pId);
if (hProcess == NULL)
{
goto FreeAndExit;
}
// Allocate memory from remote process
lpCodeMemory = VirtualAllocEx(hProcess, NULL, THREADSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (lpCodeMemory == NULL)
{
goto FreeAndExit;
}
// Query the page information
ZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
szRet = VirtualQueryEx(hProcess, lpCodeMemory, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
if (szRet == 0)
{
goto FreeAndExit;
}
// Modify the page protection for write
bRetVal = VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
if (! bRetVal)
{
goto FreeAndExit;
}
// Write my code to remote process memory
bRetVal = WriteProcessMemory(hProcess, lpCodeMemory, &ThreadProc, THREADSIZE, 0);
if (! bRetVal)
{
VirtualFreeEx(hProcess, lpCodeMemory, THREADSIZE, MEM_RELEASE);
goto FreeAndExit;
}
// Modify the page protection to protect
bRetVal = VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
if (! bRetVal)
{
goto FreeAndExit;
}
// Fill in the parameter
ZeroMemory(&myRemotePara, sizeof(RemotePara));
CreateParameter((PRemotePara)&myRemotePara);
// Allocate memory in the remote process to store the parameter
pRemotePara = (PRemotePara)VirtualAllocEx(hProcess, NULL, sizeof(RemotePara), MEM_COMMIT, PAGE_READWRITE);
if (pRemotePara == NULL)
{
VirtualFreeEx(hProcess, lpCodeMemory, THREADSIZE, MEM_RELEASE);
goto FreeAndExit;
}
// Query page information
ZeroMemory(&mbi, sizeof(MEMORY_BASIC_INFORMATION));
szRet = VirtualQueryEx(hProcess, pRemotePara, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
if (szRet == 0)
goto FreeAndExit;
// Modify page protection for write
bRetVal = VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &mbi.Protect);
if (! bRetVal)
goto FreeAndExit;
// Write para to the remote process’s memory
bRetVal = WriteProcessMemory(hProcess, pRemotePara, &myRemotePara, sizeof(myRemotePara), 0);
if (! bRetVal)
{
VirtualFreeEx(hProcess, lpCodeMemory, THREADSIZE, MEM_RELEASE);
VirtualFreeEx(hProcess, pRemotePara, sizeof(RemotePara), MEM_RELEASE);
goto FreeAndExit;
}
// Modify page protection to protect
bRetVal = VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect, &dwOldProtect);
if (! bRetVal)
goto FreeAndExit;
// Create remote thread
hThread = CreateRemoteThread(hProcess, 0, 0, lpCodeMemory, pRemotePara, 0, &dwByteWrite);
if (hThread == NULL)
{
VirtualFreeEx(hProcess, lpCodeMemory, THREADSIZE, MEM_RELEASE);
VirtualFreeEx(hProcess, pRemotePara, sizeof(RemotePara), MEM_RELEASE);
goto FreeAndExit;
}
bRet = TRUE;
FreeAndExit:
if (hProcess != NULL) CloseHandle(hProcess);
if (hToken != NULL) CloseHandle(hToken);
return bRet;
}
//
// @Name: CreateParameter
// @Author: luoluo
// @Time: 2005-04-17
// @Param: pRemotePara will be filled with data
// @Ret: if success return TRUE else return FALSE
//
BOOL WINAPI CreateParameter(PRemotePara pRemotePara)
{
HMODULE hModule;
BOOL bRet;
bRet = TRUE;
hModule = LoadLibrary("Kernel32.dll");
pRemotePara->dwGetModuleHandle = (DWORD)GetProcAddress(hModule, "GetModuleHandleA");
pRemotePara->dwGetProcAddress = (DWORD)GetProcAddress(hModule, "GetProcAddress");
pRemotePara->dwLoadLibrary = (DWORD)GetProcAddress(hModule, "LoadLibraryA");
pRemotePara->dwVirtualQuery = (DWORD)GetProcAddress(hModule, "VirtualQuery");
pRemotePara->dwVirtualProtect = (DWORD)GetProcAddress(hModule, "VirtualProtect");
hModule = LoadLibrary("User32.dll");
pRemotePara->dwMessageBox = (DWORD)GetProcAddress(hModule, "MessageBoxA");
hModule = LoadLibrary("Ntdll.dll");
pRemotePara->dwZeroMemory = (DWORD)GetProcAddress(hModule, "RtlZeroMemory");
hModule = LoadLibrary("Msvcrt.dll");
pRemotePara->dw_stricmp = (DWORD)GetProcAddress(hModule, "_stricmp");
strcpy(pRemotePara->lpLibName, "User32.dll/0");
strcpy(pRemotePara->lpHookApiName, "MessageBoxW/0");
strcpy(pRemotePara->lpImagehlp, "Imagehlp.dll/0");
strcpy(pRemotePara->lpImageDirectoryEntryToData, "ImageDirectoryEntryToData/0");
strcpy(pRemotePara->lpKernel32, "Kernel32.dll/0");
FreeAndExit:
return bRet;
}