当前位置:编程学习 > 网站相关 >>

注入进程实现星号查看

作者:Fypher 摘自:易做图八进制信

前段时间做了个查看星号密码框的工具。本以为挺简单的向星号密码文本框控件发送一个WM_GETTEXT消息就行了。这也是网上关于星号查看最流行的一种说法。然而根据我的测试这种方法是错误的!根本得不到任何内容,我猜测如果获得WM_GETTEXT消息的是一个星号密码框,Windows便会检测该消息的来源,若来自其它进程只则返回一个空字符串。
在Win98的时代这个方法也许会有效吧……

另外网上还有一种比较流行的说法是先向目标文本框发送EM_SETPASSWORDCHAR消息,以0作为wParam,去掉其密码遮盖符,再发送WM_GETTEXT消息取得文本框的内容,最后再次发送EM_SETPASSWORDCHAR消息恢复目标文本框的密码遮盖符。我测试该方法时不知为什么成功率非常非常低,大家可以去试试。

虽然向别的进程发送WM_GETTEXT消息不成功,但是通过WM_GETTEXT消息是肯定可以获得自己进程的文本框的内容的,于是我产生了一个想法:我们可以先注入文本框所属的进程,再通过该进程本身向文本框发送WM_GETTEXT消息,取得文本框内容后再将此内容发回给我们的程序!

以下是代码实现:

首先需要一个定时器Timer用于检测鼠标的位置。(当然也可以通过安装鼠标钩子实现)
在Timer的回调函数中,应该实现以下功能:
复制内容到剪贴板
代码:
GetCursorPos(&point);
//取得星号密码框的句柄
hwndFromPoint=WindowFromPoint(point)
//注入hwndFromPoint所在的进程以星号获取密码
StarInj(hwndFromPoint);
现在看看这个StarInj函数,该函数应该实现以下功能:
复制内容到剪贴板
代码:
//获得远程进程的PID
GetWindowThreadProcessId(hwndFromPoint,&dwProcessId);
//接着获得内核对象
hRemoteProcess=OpenProcess(……,dwProcessId);
//最后在远程进程中创建一个线程来执行ThreadProc函数,pRaram为传递给ThreadProc函数的参数
CreateRemoteThread(hRemoteProcess,……,ThreadProc, pParam,……);
于是,问题转化为了ThreadProc函数应该如何编写?我们先看看ThreadProc函数需实现的大致功能:
复制内容到剪贴板
代码:
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);   
}
至此,任务完全明确了。但是不要忘了Windows的内存管理方式:每个进程独享4G空间,互不干涉。因此以上代码还会产生很多问题!

1、ThreadProc并不在远程进程的地址空间中。也就是说传递给CreateRemoteThread的地址值在远程进程的地址空间中并不是ThreadProc函数的内容。
2、用于保存密码的局部变量str也不在远程进程的地址空间中,因为变量会放在本地进程的栈里。
3、ThreadProc应该如何去取得hwndFromPoint和hwndLocal呢?
4、SendMessage只不过是我们模块的输入节中形式替换程序的地址,并非SendMessage函数在远程进程中的实际地址!

现在我们来解决这些问题。

首先需要定义一个数据结构RemotePara,里面包含ThreadProc函数需要用到的一切数据,即:SendMessage函数的真实地址、hwndFromPoint和hwndLocal的值,以及需要用到的字符串str:
复制内容到剪贴板
代码:
typedef struct _RemotePara{
        DWORD dwSendMessage;
        DWORD hwndRemote;
        DWORD hwndLocal;
        char str[256];
}RemotePara;

RemotePara myRemotePara;
现在只需要正确的初始化myRemotePara,然后将它的地址作为ThreadProc的参数传递给CreateRemoteThread函数就行了。
当然,由于myRemotePara和ThreadProc都不在远程进程的地址空间中,所以我们必须在调用CreateRemoteThread之前把myRemotePara数据和ThreadProc函数都写入到远程进程的地址空间中。

现在来看看正确的代码吧

1、正确的ThreadProc函数实现:
复制内容到剪贴板
代码:
//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;
}
2、正确的Timer回调函数实现:
复制内容到剪贴板
代码:
//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);
}
3、正确的StarInj函数实现(本程序最关键的函数):
复制内容到剪贴板
代码:
//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
部分文章来自网络,