您的位置:首页 > 其它

应用程序的 DIY__(给程序加上新功能)

2015-09-04 16:14 295 查看
原始排版:应用程序的 DIY__(给程序加上新功能)

标签(空格分隔): R3 窗口编程

开篇

之前的考试中最后一个实操题就是要在记事本上加入一个功能。(通过 按钮 或者 菜单项来实现)

动还是静

从静开始

这个问题的由来是 这个控件本身到底应该动态创建还是静态创建,本身是取决于原有应用程序的
资源
, 如果原本的应用程序是存在有窗口资源或者是菜单资源,那么我们静态创建也是无妨的,通过
ResHacker
等工具可以轻易做到,过程比较简单,找到窗口的资源后,写入一个控件资源即可。

这是 Windows Xp 下的计算器的窗口资源

CONTROL "1/x", 107, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 140, 85, 24, 18
CONTROL "sqt", 103, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 140, 45, 24, 18
CONTROL "%", 109, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 142, 64, 20, 18
CONTROL "help", 333, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 148, 23, 20, 19
CONTROL "", 1000, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 0, 127, 1, 1


我在其中添加了一个
Caption
为 “help” 的按钮,资源ID为
333


在最新版本的
ResHacker
也支持可视化的资源编辑器,可以直接右键 “Insert control”。

菜单资源的话也是同样的道理。

到动结束

换一个例子,当我们去读取 Win7 的计算器时就会发现,其静态资源区是找不到 窗口资源和菜单资源的,反正我是没找到。

这个时候怎么办?

最简单的方法 莫过于 调用 CreateWidowsEx 来创建一个按钮出来。

不过后来我发现创建按钮的话由于种种原因并不可靠。

不过也有应对的方法就是添加
菜单项
,这个就我目前测试来说比较可靠。

HWND hWnd = FindWindow(L"SciCalc", L"计算器");
AppendMenu(GetMenu(hWnd), MF_STRING, 123, L"Hello");


当然这个过程并不是由本地调用,而是由应用程序去调用

驻进目标应用程序___dll注入

动还是静

驻进也分为动静两种:

一、 远程线程注入

二、 导入表注入

两种各有优劣,自行斟酌。

从远程线程注入说起,也就是从动说起:

bool InjectDll(DWORD dwPid, char *pszLibFileName)
{

HANDLE hProcess = OpenProcess(

PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD |     // For CreateRemoteThread
PROCESS_VM_OPERATION |      // For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE,           // For WriteProcessMemory
//, PROCESS_VM_READ ,       //  For CreateRemoteThread
/*  PROCESS_ALL_ACCESS,*/
FALSE, dwPid);

PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L"Kernel32"), "LoadLibraryA");
//计算DLL路径名需要的内存空间
int cb = (1 + lstrlenA(pszLibFileName)) * sizeof(char);
//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名缓冲区
char *pszLibFileRemote = (char *)VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
//使用WriteProcessMemory函数将DLL的路径名复制到远程进程的内存空间
bool iReturnCode = WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)pszLibFileName, cb, NULL);
CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, pszLibFileRemote, 0, NULL);
CloseHandle(hProcess);
return true;
}


这个代码的 健壮性很差,代码中并没有
return false
的处理,是临时拼凑出来解释动这一情况的。

接下来说静:

这个说起来就很简单了,

使用
LoadPE
这一类型的工具,直接将 DLL 添加到 原应用程序的导入表就行了。

这里需要注意的是,这个
dll
的写法。

DWORD WINAPI ThreadProc(
_In_  LPVOID lpParameter
)
{
//
// 延时 500 毫秒 等待窗口创建完成
//
Sleep(500);
HWND hWnd = FindWindow(L"SciCalc", L"计算器");
// AppendMenu(GetMenu(hWnd), MF_STRING, 123, L"Hello");
g_uOldProc = GetWindowLong(hWnd, GWL_WNDPROC);
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWindowProc);
return 0;
}


DllMain如下:

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
//
// 延时几秒 等待窗口创建成功
//
CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}


需要多创建一条线程出来,等待窗口创建完成。

尾声,消息的拦截

这里消息拦截是 使用的
SetWindowLong
这个API。 这个API 可以用来替换掉原来的消息回调函数地址,我们就可以实现一个中间过滤的功能。

GetWindowLong
是用来获取 消息回调函数地址,把老的地址记录,替换上新的地址,

使用
CallWindowProc
继续下发消息,看起来是不是有点像是 SSDT Inline HOOK呢?

LONG g_uOldProc;

LRESULT CALLBACK MyWindowProc(
_In_  HWND hwnd,
_In_  UINT uMsg,
_In_  WPARAM wParam,
_In_  LPARAM lParam
)
{
if (uMsg == WM_COMMAND && LOWORD(wParam) == 333)
{
MessageBox(0, 0, 0, 0);
}

return CallWindowProc((WNDPROC)g_uOldProc, hwnd, uMsg, wParam, lParam);
}


后话

实现方法远远不止上面列举的几种,例如还可以设置全局消息钩子等,各种各样的方法,不应该局限于眼前。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: