需求背景
动态修改程序的函数oldsub()执行我们的newsub()
此时则需要注入并hook
注入
简单的远程线程注入分三步
//获取进程句柄
//提升权限
//注入dll
#include <windows.h>
//获取进程句柄
HANDLE GetThePidOfTargetProcess(HWND hwnd)
{
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcee = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, pid);
return hProcee;
}
//提升权限
void Up()
{
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
//进程注入
BOOL DoInjection(char *DllPath, HANDLE hProcess)
{
DWORD BufSize = strlen(DllPath)+1;
LPVOID AllocAddr = VirtualAllocEx(hProcess, NULL, BufSize, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(hProcess, AllocAddr, DllPath, BufSize, NULL);
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
HANDLE hRemoteThread;
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL);
if (hRemoteThread)
{
MessageBox(NULL, TEXT("注入成功"), TEXT("提示"), MB_OK);
return true;
}
else
{
MessageBox(NULL, TEXT("注入失败"), TEXT("提示"), MB_OK);
return false;
}
}
int main()
{
//这里填写窗口标题
HWND hwnd=FindWindowExA(NULL, NULL, NULL, "任务管理器");
Up();
HANDLE hP = GetThePidOfTargetProcess(hwnd);
//开始注入
//这里填写Dll路径
DoInjection("E:\\studio\\VS2017\\F2H1.MessageBox\\x64\\Release\\F2H1.MessageBox.dll", hP);
}
参考:
https://github.com/suvllian/process-inject
https://github.com/suvllian/process-inject
hook
方式1:通过注入dll到目标进程进行,可以替换kernelbase.dll里面的OpenProcess的前面5个字节为jmp跳转到我们自己的地址,也可以修改目标进程的IAT.
方式2:通过WriteProcessMemory写入代码,修改目标进程的OpenProcess跳转到我们的代码
// 设置hook https://bbs.pediy.com/thread-250631.htm
void* setReturn1(int toAddr, int fromAddr) {
int isize = 5 + 5 + 5;
char *p1 = (char*)VirtualAlloc(0, isize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memset(p1, 0, isize);
char *p = (char*)&return1;
// 改用汇编,不然Release编译时会出错
// memcpy(p1, p, isize);
__asm {
pushad;
mov esi, p;
mov edi, p1;
mov ecx, isize;
rep movsb;
popad;
}
// 目标地址 - (当前地址 + 指令长度)
int fix1 = toAddr - ((int)p1 + 5);
int fix2 = (fromAddr + 5) - ((int)p1 + 0xA + 5); // ret addr
int fix3 = (int)p1 - (fromAddr + 5);
*(int*)((int)p1 + 1) = fix1;
*(int*)((int)p1 + 0xB) = fix2;
// hook
DWORD flOldProtect;
VirtualProtect((LPVOID)fromAddr, 5, PAGE_EXECUTE_READWRITE, &flOldProtect);
*(BYTE*)fromAddr = 0xE9; // JMP x
*(int*)(fromAddr + 1) = fix3; // JMP x
VirtualProtect((LPVOID)fromAddr, 5, flOldProtect, &flOldProtect);
return p1;
}
hook库对比:
nthookengine //支持x64 开源
mhook //支持x64 开源 https://github.com/martona/mhook
Detour//x64收费 https://github.com/microsoft/Detours
https://blog.csdn.net/zhuhuibeishadiao/article/details/51170608
寻址
通过LoadLibrary加载kernelbase.dll模块基地址.
通过GetProcAddress获取OpenProcess的地址.
方式2:编程直接引用OpenProcess的地址,因为在Windows下3大模块user32.dll,kernelbase.dll,ntdll.dll的加载基地址在每个应用程序中都是一样的.
方式3:通过寻找目标的IAT找到OpenProcess
内存中特征码匹配参考:
https://bbs.pediy.com/thread-121198.htm
https://blog.csdn.net/HoneyCat/article/details/3950939
参考:
hook原理:https://bbs.pediy.com/thread-228669.htm