标签:real tput int text 重复 步骤 nap 下载链接 oid
最近工作中遇到一个问题,需要通过程序界面进行判断程序的运行状态,刚开始认为很简单,不就是一个窗体控件获取,获取Button的状态和Text。刚好去年干过该事情,就没太在意,就把优先级排到后面了,随着项目交付时间的临近,就准备开始解决问题,一下懵逼了,这次软件作者也聪明了,居然换了花样。
从图中可以发现,此处的按钮上的文字等信息不是通过Button信息进行操作。静想猜测是通过Windows API直接将信息进行写入,那么哪个API可以进行写入呢,想想不难发现,其实就是窗口程序中在窗口中写入文字的方法DrawText,同时隐约记得SetWindowsText也具备该功能。既然有猜想了那就实践看看,验证下猜想。
开干之前,还需要理理思路:
BOOL WINAPI DetourCreateProcessWithDll(LPCSTR lpApplicationName,
LPSTR lpCommandLine,
...);
BOOL WINAPI DetourContinueProcessWithDll(HANDLE hProcess, LPCSTR lpDllName);
经过上面几个步骤下来,已经有了完整的思路,下文主要结合实践,进行代码实践。本文主要从如下几个方面进行时间:
首先,按照Detours的编程规范,需要在加载HookWindowTextDll时通过方法DetourFunctionWithTrampoline进行注册。在卸载的时候通过DetourRemove卸载。
该处主要分以下几步:
首先需要声明我们的方法
BOOL WINAPI MySetWindowTextA( HWND hWnd, LPCTSTR lpString );
BOOL WINAPI MySetWindowTextW( HWND hWnd, LPCWSTR lpString );
int WINAPI MyDrawTextA( HDC hDC, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat );
int WINAPI MyDrawTextW( HDC hDC, LPCWSTR lpString, int nCount, LPRECT lpRect, UINT uFormat );
//该方法主要是用Real_SetWindowTextA保存原来函数SetWindowTextA地址,方便后面调用
DETOUR_TRAMPOLINE( BOOL WINAPI Real_SetWindowTextA( HWND a0, LPCTSTR a1 ), SetWindowTextA );
DETOUR_TRAMPOLINE( BOOL WINAPI Real_SetWindowTextW( HWND a0, LPCWSTR a1 ), SetWindowTextW );
DETOUR_TRAMPOLINE( int WINAPI Real_DrawTextA( HDC a0, LPCTSTR a1, int a2, LPRECT a3, UINT a4 ), DrawTextA );
DETOUR_TRAMPOLINE( int WINAPI Real_DrawTextW( HDC a0, LPCWSTR a1, int a2, LPRECT a3, UINT a4 ), DrawTextW );
//代码实现,限于篇幅,仅列出MySetWindowTextA
BOOL WINAPI MySetWindowTextA( HWND hWnd, LPCTSTR lpString )
{
#ifdef _DEBUG
char strMsg[ 1024 ]={0};
wsprintf( strMsg, "SetWindowTextA : %s. size = %ld\n", lpString, strlen(lpString) );
OutputDebugString( strMsg );
#endif
return Real_SetWindowTextA( hWnd, lpString );
}
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
if( DLL_PROCESS_ATTACH == ul_reason_for_call )//dll加载
{
InstallProbes();
}
else if( DLL_PROCESS_DETACH == ul_reason_for_call )//dll卸载
{
UninstallProbes();
}
else;
return TRUE;
}
拦截注入通过方法DetourFunctionWithTrampoline进行,该方法原型如下:
BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline,
PBYTE pbDetour);
这个函数有两个参数,pbTrampoline和一个指向pbDetour函数的指针。目标函数Target之所以没有作
为一个参数,是因为它已经编码到pbTrampoline函数之中(上文中进行编码DETOUR_TRAMPOLINE)。
BOOL InstallProbes()
{
DetourFunctionWithTrampoline( (PBYTE)Real_SetWindowTextA, (PBYTE)MySetWindowTextA );
DetourFunctionWithTrampoline( (PBYTE)Real_SetWindowTextW, (PBYTE)MySetWindowTextW );
DetourFunctionWithTrampoline( (PBYTE)Real_DrawTextA, (PBYTE)MyDrawTextA );
DetourFunctionWithTrampoline( (PBYTE)Real_DrawTextW, (PBYTE)MyDrawTextW );
OutputDebugString("InstallProbesA ok.\n");
return TRUE;
}
BOOL UninstallProbes()
{
DetourRemove( (PBYTE)Real_SetWindowTextA, (PBYTE)MySetWindowTextA );
DetourRemove( (PBYTE)Real_SetWindowTextW, (PBYTE)MySetWindowTextW );
OutputDebugString("UNInstallProbesB ok.\n");
return TRUE;
}
至此拦截注入的方法就完成。下一小节就是如何进行动态注入了。
既然要动态注入,那么就先要看看动态注入方法DetourContinueProcessWithDll方法的使用方法
//把一个动态链接库注入到一个新的进程中
BOOL WINAPI DetourContinueProcessWithDllA(HANDLE hProcess, LPCSTR lpDllName)
该方法有两个参数,一看看就明白了
那么此时应该先获取进程句柄,获取进程句柄通过如下方法即可:
DWORD GetProcessIdFromProcessName(std::string processname)
{
DWORD dwRet = 0;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap != INVALID_HANDLE_VALUE)
{
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
while (bMore)
{
if (boost::iequals(pe32.szExeFile, processname))
{
dwRet = pe32.th32ProcessID;
break;
}
bMore = ::Process32Next(hProcessSnap, &pe32);
}
::CloseHandle(hProcessSnap);
}
return dwRet;
}
调用测试:
std::string str1 = "WireCut.EXE";
DWORD dwProcessId = GetProcessIdFromProcessName(str1);
std::cout << dwProcessId << std::endl; //
获取到了进程,那就进入下一节,获取句柄。
OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄
HANDLE OpenProcess(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
DWORD dwProcessId
);
参数:
返回类型:
HANDLE GetProcessHandle(DWORD nID)
{
//PROCESS_ALL_ACCESS 所有能获得的权限
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, nID);
}
DWORD dwProcessId = GetProcessIdFromProcessName("WireCut.EXE");
if (dwProcessId != 0)
{
bRet = DetourContinueProcessWithDllW(GetProcessHandle(dwProcessId), szDllFilePath);
}
到此就完成了所有工作,后面提供项目代码和库文件
链接:https://pan.baidu.com/s/1c09LWg9zo5NIVwR2htJYZA
提取码:f0kt
欢迎关注交流共同进步
博客地址:wqliceman.top
标签:real tput int text 重复 步骤 nap 下载链接 oid
原文地址:https://www.cnblogs.com/wqliceman/p/10924958.html