注入进程实现星号查看
作者:Fypher 摘自:易做图八进制信
前段时间做了个查看星号密码框的工具。本以为挺简单的向星号密码文本框控件发送一个WM_GETTEXT消息就行了。这也是网上关于星号查看最流行的一种说法。然而根据我的测试这种方法是错误的!根本得不到任何内容,我猜测如果获得WM_GETTEXT消息的是一个星号密码框,Windows便会检测该消息的来源,若来自其它进程只则返回一个空字符串。
在Win98的时代这个方法也许会有效吧……
另外网上还有一种比较流行的说法是先向目标文本框发送EM_SETPASSWORDCHAR消息,以0作为wParam,去掉其密码遮盖符,再发送WM_GETTEXT消息取得文本框的内容,最后再次发送EM_SETPASSWORDCHAR消息恢复目标文本框的密码遮盖符。我测试该方法时不知为什么成功率非常非常低,大家可以去试试。
虽然向别的进程发送WM_GETTEXT消息不成功,但是通过WM_GETTEXT消息是肯定可以获得自己进程的文本框的内容的,于是我产生了一个想法:我们可以先注入文本框所属的进程,再通过该进程本身向文本框发送WM_GETTEXT消息,取得文本框内容后再将此内容发回给我们的程序!
以下是代码实现:
首先需要一个定时器Timer用于检测鼠标的位置。(当然也可以通过安装鼠标钩子实现)
在Timer的回调函数中,应该实现以下功能:复制内容到剪贴板现在看看这个StarInj函数,该函数应该实现以下功能:代码:
GetCursorPos(&point);
//取得星号密码框的句柄
hwndFromPoint=WindowFromPoint(point)
//注入hwndFromPoint所在的进程以星号获取密码
StarInj(hwndFromPoint);复制内容到剪贴板于是,问题转化为了ThreadProc函数应该如何编写?我们先看看ThreadProc函数需实现的大致功能:代码:
//获得远程进程的PID
GetWindowThreadProcessId(hwndFromPoint,&dwProcessId);
//接着获得内核对象
hRemoteProcess=OpenProcess(……,dwProcessId);
//最后在远程进程中创建一个线程来执行ThreadProc函数,pRaram为传递给ThreadProc函数的参数
CreateRemoteThread(hRemoteProcess,……,ThreadProc, pParam,……);复制内容到剪贴板至此,任务完全明确了。但是不要忘了Windows的内存管理方式:每个进程独享4G空间,互不干涉。因此以上代码还会产生很多问题!代码:
DWORD _stdcall ThreadProc(void *pParam){
char str[256];
//向星号文本框发送WM_GETTEXT消息,取得密码后放入str变量中
SendMessage(hwndFromPoint,WM_GETTEXT,(WPARAM)255,(LPARAM)str);
//将str的内容发回给我们的本地进程的文本框,即将密码显示出来
//hwndLocal是本地进程用来显示密码的文本框的句柄
SendMessage(hwndLocal,WM_SETTEXT,NULL,(LPARAM)str);
}
1、ThreadProc并不在远程进程的地址空间中。也就是说传递给CreateRemoteThread的地址值在远程进程的地址空间中并不是ThreadProc函数的内容。
2、用于保存密码的局部变量str也不在远程进程的地址空间中,因为变量会放在本地进程的栈里。
3、ThreadProc应该如何去取得hwndFromPoint和hwndLocal呢?
4、SendMessage只不过是我们模块的输入节中形式替换程序的地址,并非SendMessage函数在远程进程中的实际地址!
现在我们来解决这些问题。
首先需要定义一个数据结构RemotePara,里面包含ThreadProc函数需要用到的一切数据,即:SendMessage函数的真实地址、hwndFromPoint和hwndLocal的值,以及需要用到的字符串str:复制内容到剪贴板现在只需要正确的初始化myRemotePara,然后将它的地址作为ThreadProc的参数传递给CreateRemoteThread函数就行了。代码:
typedef struct _RemotePara{
DWORD dwSendMessage;
DWORD hwndRemote;
DWORD hwndLocal;
char str[256];
}RemotePara;
RemotePara myRemotePara;
当然,由于myRemotePara和ThreadProc都不在远程进程的地址空间中,所以我们必须在调用CreateRemoteThread之前把myRemotePara数据和ThreadProc函数都写入到远程进程的地址空间中。
现在来看看正确的代码吧
1、正确的ThreadProc函数实现:复制内容到剪贴板2、正确的Timer回调函数实现:代码:
//by Fypher
DWORD _stdcall ThreadProc(RemotePara *lpPara){
//定义函数指针pSendMessage,目的是用来指向真实的SendMessage函数地址
typedef BOOL (WINAPI *pSendMessage)(HWND,UINT,WPARAM,LPARAM);
pSendMessage mySendMessage;
//从myRemotePara参数中得到SendMessage函数的地址
mySendMessage=(pSendMessage)lpPara->dwSendMessage;
//取得星号密码框的内容,放入lpPara->str中
mySendMessage((HWND)(lpPara->hwndRemote),WM_GETTEXT,
(WPARAM)255,(LPARAM)lpPara->str);
//将lpPara->str的内容发回给我们的本地进程的文本框,即将密码显示出来
mySendMessage((HWND)(lpPara->hwndLocal),WM_SETTEXT,
NULL,(LPARAM)lpPara->str);
return 0;
}复制内容到剪贴板3、正确的StarInj函数实现(本程序最关键的函数):代码:
//by Fypher
void Dlg_OnTimer(HWND hwnd, UINT id){
POINT point;
GetCursorPos(&point);
//取得星号文本框的句柄
HWND hwndFromPoint=WindowFromPoint(point);
if(!hwndFromPoint)
return;
//取得本地程序用来显示密码的文本框的句柄
HWND hwndLocal=GetDlgItem(hwndAPP,IDC_STAR_CONTENT);
//开始工作,呵呵
StarInj(&hwndFromPoint,&hwndLocal);
}复制内容到剪贴板代码:
//by Fypher
void StarInj(HWND hwndRemote,HWND hwndLocal){
const DWORD THREADSIZE=2048;
DWORD ThreadId;
DWORD dwProcessId=NULL;
//得到星号文本框所属进程的ID
GetWindowThreadProcessId(hwndRemote,&dwProcessId);
if(!dwProcessId)
return;
//取得该进程内核对象
HANDLE hRemoteProcess = OpenProcess(PROCESS_CREATE_THREAD| //申请创建线程的权限
PROCESS_VM_OPERATION| //申请分配空间的权限
PROCESS_VM_WRITE, //申请写入空间的权限
&nb补充:综合编程 , 安全编程 ,
上一个:监控一下另外一台电脑是否有人使用
下一个:如何学习编程(二)CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,