应用程序的 DIY__(给程序加上新功能)
来源:互联网 发布:达芬奇14mac怎么改中文 编辑:程序博客网 时间:2024/05/01 07:14
原始排版:应用程序的 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);}
后话
实现方法远远不止上面列举的几种,例如还可以设置全局消息钩子等,各种各样的方法,不应该局限于眼前。
- 应用程序的 DIY__(给程序加上新功能)
- 给MFC应用程序加上全屏幕的功能
- 怎么给自己的程序加上图标
- 给我的程序加上托盘
- 给程序加上漂亮的注释!!!
- 给程序加上皮肤
- 给android程序加上声音
- 给Qt生成的exe程序加上漂亮的图标
- 给纯SDK程序加上自己的ICO图标
- 给纯SDK程序加上自己的ICO图标
- 给纯SDK程序加上自己的ICO图标
- 给多窗口的程序加上多标签
- 案例_怎么给自己的程序加上试用次数
- Qt给自己写的程序加上图标
- 如何给QT应用程序加上图标
- 给VC/SDK中的应用程序加上皮肤(SKinSharp的皮肤库)
- 如何给终端程序加上图标
- C#给程序加上特定皮肤
- PAT 1083. List Grades (25)
- QQ空间g_tk算法的JS脚本的获取和分析
- Clothes
- 代沐研:非农战幕终拉开,金银油空头强袭
- 忆昔悟今
- 应用程序的 DIY__(给程序加上新功能)
- 9.3 - 抗战胜利日
- 自我学习
- strcpy,strnpy和strlcpy的区别
- Codeforces 460d Littel victor and set
- usaco Longest Prefix
- 二进制中1的个数
- SQL存储过程+事务 常用实例
- 剑指offer整理归纳(2/2)