获取其它进程密码框中的密码


程序编写的过程中,往往有些功能需要由其它的进程权限才能够完成这些工作,如得到其它进程中某个窗口的标题;建立隐藏的守护进程来监测本进程的运行情况;在Win7下,利用其它有高UAC权限的进程来完成一些功能等等。都需要使用到其它进程来完成这些工作。本文就来讲解如何获取其它进程中密码框中的密码。

以上代码实现及理论均为Win32平台为主。

A. 为什么选择远程线程 ?

我们知道,远程线程就是想让其它线程执行我们自己的代码,如果要想使自己的代码被其它进程执行,首先能想到的就是DLL,因为DLL可以被其它进程附加,并且可以执行所有的功能。但强大的功能也需要一个导火索来给它这个机会爆发,因为在进程运行进来后,LoadLibrary仍然可以使一个动态库附加映射进某个进程,但当我们执行LoadLibrary时,是在自己进程中执行的,无法使其它进程有机会执行这个代码,从而也就没机会使我们的代码附加到其它进程中,结果就是,强大的代码永远没有得到一个可以执行的机会。

而远程线程就是系统提供给我们的一个伯乐,它可以在你创建线程时,指定一个起始运行的入口,这样LoadLibrary就有了执行的机会,从而,DLL里面的代码就是会一气呵成的执行。

所以远程线程是必须的。

B. 一些必须了解的概念

1.  地址空间

在Win32平台下(Linux及主流平台),每个进程拥有4GB独立的地址空间,一般叫做线程地址空间,相对于每个进程来说,在自己的空间内访问一些地址内容,即访问变                量的值及执行一些代码都是非常方便的有效的,每个进程完成自己的工作,相互不会产生任何干扰。

2.  远程线程

一般而言,线程是线程可调试,实际完成一些工作(即执行一些代码)的最小实体,一个进程可以包含一个及以上的线程,这些线程并行工作,完成实际的功能。而远                程线程,故名思议,即非本进程的线程。假设有A,B两个进程,远程线程就是由A进程创建,但运行于B进程的地址空间中,拥有B进程的进程权限。

3.  代码注入

代码注入就是,将精心准备好的代码(即数据)放进某个进程的地址空间中。

C.  为什么不选择DLL的方式 ?

前面已经提到过,DLL里面就是可以执行的代码,我们只需要将DLL附加进进程就得以机会去执行这些代码。但DLL是以文件形式存放在磁盘中,有些功能可能会很                    小,或者有些功能需要隐藏一些实现细节,如果附加一个DLL的话,效果并不是那么的友好,所以如果有机会不用DLL,依然能够使远程线程实现强大的功能,那自然                是最佳选择,但这也使得代码编写起来更难,也就需要更强的编程的基本功。

D. 需要使用到的主要API(以Win32平台为例)

OpenProcess:打开一个进程,得到该进程的句柄。

VirtualAllocEx:简言之为在指定的进程中申请一些空间。

WriteProcessMemory:简言之为在指定进程中写入一些数据。

CreateRemoteThread:在指定的进程中创建一个线程。

E.      具体实现 -- Talk is cheap, show me the code! (Linus)

以得到其它进程中某一窗体的标题为例,来简单的介绍远程线程的用法。

得到一个窗口的标题,一般会调用 GetWindowText,它的使用方法如下:

The GetWindowText function copies the text of the specified window's titlebar (if it has one) into a buffer. If the specified window is a control, thetext of the control is copied. However, GetWindowText cannot retrievethe text of a control in another application.

上面的使用方法是摘自MSDN上GetWindowText的描述,从描述中可以看到,GetWindowText不能够得到其它应用程序的标题,即一个进程的程序不能获得其它进程窗口的句柄。但如果那段代码是由其它进程来执行,执行后我们再得到结果,是不是就可以做到了呢。

假设我们的进程为A,我们想得到B进程中某一个控制的标题,要想完成以上功能,首先我们要能让我们的代码放到B进程的地址空间中,其次让B执行这些代码,最后从B进程中得到执行的结果。

代码实现如下(为突出有效代码,合法性检测都没有添加):

#include <iostream>
#include <windows.h>

using namespace std;

void Test();

void main()
{
 Test();
}


__declspec(naked) void __stdcall GetWindowTextSpy(DWORD dwParam)
{
 _asm
 {
  mov  eax, [esp + 4]        // 得到传入的参数 dwParam, 此时为窗口句柄
  push    [eax + 0]        // 缓冲区长度
  mov  ebx, eax
  add  ebx, 8
  push    ebx       // 缓冲区地址
  push  [eax + 4]     // 目标窗口句柄
  call GetWindowText
  ret  4
 }
}

__declspec(naked) void __stdcall EndLabel(DWORD dwParam)
{
}


void Test()
{

 // 得到目标窗口所在进程的ID,篇幅原因假设已经知道窗口句柄
 HWND hwnd  = (HWND)0x000108F8;
 DWORD dwProcessID;
 DWORD dwTitleSize = 0x20;
 DWORD dwDataLen = 0x30;

 GetWindowThreadProcessId(hwnd, &dwProcessID);

 HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
          PROCESS_VM_READ, FALSE, dwProcessID);
 // 在B 进程中申请空间以存放返回的窗口标题
 LPBYTE pData  = (LPBYTE)VirtualAllocEx(hProcess, 0, dwDataLen, MEM_COMMIT, PAGE_READWRITE);

 // 填充参数
 WriteProcessMemory(hProcess, pData, &dwTitleSize, 4, NULL);
 WriteProcessMemory(hProcess, pData + 4, &hwnd, 4, NULL);

 // 注入的代码长度
 DWORD dwCodeLen = 0;

#ifdef _DEBUG
 const DWORD dwSpyRealAddr = *(LPDWORD)((LPBYTE)(&GetWindowTextSpy)+1) + (DWORD)(&GetWindowTextSpy) + 5;
 const DWORD dwEndReadAddr = *(LPDWORD)((LPBYTE)(&EndLabel)+1) + (DWORD)(&EndLabel) + 5;
#else
 const DWORD dwSpyRealAddr = (DWORD)GetWindowTextSpy;
 const DWORD dwEndReadAddr = (DWORD)EndLabel;
#endif

 dwCodeLen = dwEndReadAddr - dwSpyRealAddr;

 LPBYTE pCode = (LPBYTE)VirtualAllocEx(hProcess, 0, dwCodeLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 LPBYTE pCodeBuff = (LPBYTE)malloc(dwCodeLen);
 memcpy((LPVOID)pCodeBuff, (LPVOID)dwSpyRealAddr, dwCodeLen);

 // 调整代码
 LPBYTE p = pCodeBuff;
 while(*p != 0xE8){p++;}

    *(DWORD*)(p+1) = (DWORD)&GetWindowText - (DWORD)(p - (LPBYTE)pCodeBuff + (LPBYTE)pCode) - 5;
 WriteProcessMemory( hProcess, pCode, pCodeBuff, dwCodeLen, NULL);

 HANDLE hRThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pCode, pData, 0, 0);
 WaitForSingleObject(hRThread, INFINITE);

 char szTitle[100] = {0};
 DWORD dwReadBytes  = 0;
 ReadProcessMemory(hProcess, pData + 8, szTitle, dwTitleSize, &dwReadBytes);

 cout << szTitle << endl;

 CloseHandle(hRThread);
 free(pCodeBuff);
 VirtualFreeEx(hProcess, pCode, dwCodeLen, MEM_RELEASE);
 VirtualFreeEx(hProcess, pData, dwDataLen, MEM_RELEASE);   
 CloseHandle(hProcess);
}

更多详情见请继续阅读下一页的精彩内容:

  • 1
  • 2
  • 下一页

相关内容

    暂无相关文章