注入进程

注入进程
2010年11月23日
  HOOK,实际提到这个大家都知道它的功用,如果要是抓取消息那肯定是用下面的函数:
  //----------------------------------------------------------------------
  ::SetWindowsHookA(int nFilterType,HOOKPROC pfnFilterProc);
  ::CallNextHookEx(HHOOK hhk,int Code,WPARAM wParam,LPARAM lParam);
  ::UnhookWindowsHook(int nCode,HOOKPROC pfnFilterProc);
  //它们的参数我就不说了,实在是太多了!!
  //---------------------------------------------------------------------------
  今天说一种别的方法来抓取WINDOWS消息的方法,这种方法虽然有点局限性,但是感觉很不错的哦!这方法,可以抓取一个进程中的所有窗口的消息。不信就跟我一体来试试,如果看不太明白,那只好去学学相关知识了。我们选择的方法就是HOOK API的方法。网络上流传的HOOK API的很多,但是碰到的都是HOOK那个MessageBoxA函数,没什么意思,今天给一个全能的方法,我们不用了解太多PE结构,非要在IAT表中修改,我们先来看看我们要处理的API为:
  /*------------------------------------------------------------------------------------
  函数原型:LRESULT CallWindowProc(WNDPROC lpPrevWndFunc,HWND hWnd.UINT Msg,WPARAM wParam,LPARAM IParam);
  参数:
  lpPrevWndFunc:指向前一个窗口过程的指针。如果该值是通过调用GetWindowLong函数,并将该函数中的nlndex参数设为
  GWL_WNDPROC或DWL_DLGPROC而得到的,那么它实际上要么是窗口或者对话框的地址,要么就是代表该地址的句柄。
  hWnd:指向接收消息的窗口过程的句柄。
  Msg:指定消息类型。
  wParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
  IParam:指定其余的、消息特定的信息。该参数的内容与Msg参数值有关。
  返回值:返回值指定了消息处理结果,它与发送的消息有关
  -----------------------------------------------------------------------------------*/
  我想一般对这个函数,比较陌生点,用的人就不多了,就像我有时用ntdll.dll中LdrGetDllHandle这类函数一样。因为它的功能很多时候都不用知道的。
  为了能抓到消息,而且不用HOOK这类API函数,我们要在这个函数上做手脚,或许可以对DefWindowProc()这个函数也做手脚,但是我想我要一个就可以了!因为这里举例是用自定义消息为例子的,为什么要用自定义消息呢!我还想说明一点问题就是远程注入进程。
  实际对于一个进程来讲,只要给它放个DLL那么它就不得不听你的了,我们可以给这个DLL发送一些命令,让它按照命令来操作我们的目标进程。有的时候我就特别的喜欢‘该死’,他做的系统就给我们一个空间,也就是0x400-0x7FF是为用户自定义的消息,我们就可以用如下的方法来设置命令:
  #define WM_CMD_EXIT WM_USER+100 //退出进程
  #define WM_CMD_GETHWND WM_USER+101 //获取HWND句柄
  #define WM_CMD_GETCAPTION WM_USER+102 //获取窗口名称
  ……等等,我们还可以调用进程的内部函数,让进程做我们想让它做的。实际就举个例子来将,发给命令过去,让QQ不断显示广告,或定时显示广告,我们几乎就完全操作了进程了。如果没道德,想抓取别人的隐私,那也是顺手而已。可是我在发这篇贴的时候,还是想过是否要发,因为我觉得我手里的东西就是把双刃剑,能杀这边,也能杀那边。希望学会的朋友都不要把它用于搞破坏上。
  注入进程的方法太多了,我就不说了,我把它写了一个类,大家就可以拿去直接用了。
  //注意的是,路径是绝对路径,才能给其它进程注入。
  //----------------------------------------------------------------------------
  // RemoteShell.h: interface for the CRemoteShell class.
  //
  //
  #if !defined(AFX_REMOTESHELL_H__6242FFA8_B8E3_4F9A_BE7D_197F76A78D03__INCLUDED_)
  #define AFX_REMOTESHELL_H__6242FFA8_B8E3_4F9A_BE7D_197F76A78D03__INCLUDED_
  #if _MSC_VER > 1000
  #pragma once
  #endif // _MSC_VER > 1000
  #include "tlhelp32.h"
  #pragma comment(lib,"th32.lib")
  class CRemoteShell
  {
  public:
  CRemoteShell();
  virtual ~CRemoteShell();
  public:
  public:
  CString m_dllPath;
  DWORD pId;
  DWORD dwSize;
  LPVOID pDll;
  HANDLE hDll;
  HANDLE hToken;
  HANDLE hProcess;
  LUID Luid;
  TOKEN_PRIVILEGES tp;
  public:
  int Release(DWORD procId=NULL);
  int Load(LPCTSTR dllpath,DWORD pId=NULL); //进程注入
  int Load(LPCTSTR dllpath,HWND hWnd); //窗口注入
  HANDLE GetDllHandle(LPCTSTR path,DWORD pid);
  };
  #endif // !defined(AFX_REMOTESHELL_H__6242FFA8_B8E3_4F9A_BE7D_197F76A78D03__INCLUDED_)
  //-------------------------------------------------------------------------------------------
  // RemoteShell.cpp: implementation of the CRemoteShell class.
  //
  //
  #include "stdafx.h"
  #include "注入程序.h"
  #include "RemoteShell.h"
  #ifdef _DEBUG
  #undef THIS_FILE
  static char THIS_FILE[]=__FILE__;
  #define new DEBUG_NEW
  #endif
  //
  // Construction/Destruction
  //
  CRemoteShell::CRemoteShell()
  {
  hToken =NULL;
  hProcess=NULL;
  memset(&tp,0,sizeof(TOKEN_PRIVILEGES));
  //取得句柄的令牌:
  if (!OpenProcessToken(GetCurrentProcess(), //是要修改访问权限的进程句柄
  TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, //指定你所需要的操作类型
  &hToken)) //是返回的访问令牌指针
  {
  return ;
  }
  //获取权限的LUID值:
  if (!LookupPrivilegeValue(NULL, //系统的名称,如果是本地系统只要指明为NULL就可以了
  SE_DEBUG_NAME, //指明了权限的名称
  &Luid)) //返回LUID的指针
  {
  return ;
  }
  tp.PrivilegeCount = 1;
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  tp.Privileges[0].Luid = Luid;
  //访问令牌进行修改:
  if (!AdjustTokenPrivileges(hToken, //访问令牌的句柄
  0, //决定是进行权限修改还是除能(Disable)所有权限
  &tp, //指明要修改的权限,指向TOKEN_PRIVILEGES结构的指针,该结构
  包含一个数组,数据组的每个项指明了权限的类型和要进行的操作
  sizeof(TOKEN_PRIVILEGES), //是结构PreviousState的长度,如果PreviousState为空,该参
  数应为NULL
  NULL, //参数也是一个指向TOKEN_PRIVILEGES结构的指针,存放修改前
  的访问权限的信息,可空
  NULL)) //实际PreviousState结构返回的大小
  {
  return ;
  }
  }
  CRemoteShell::~CRemoteShell()
  {
  if(hToken!=NULL){::CloseHandle(hToken);}
  if(hProcess!=NULL){::CloseHandle(hProcess);}
  }
  //注入给指定进程:
  int CRemoteShell::Load(LPCTSTR dllpath,DWORD pId)
  {
  hProcess =NULL;
  pDll =NULL;
  m_dllPath =dllpath;
  //如果指定进程ID为NULL,就注入给自己.
  if(pId==NULL){pId=::GetCurrentProcessId();}
  //打开进程:
  hProcess=::OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,1,pId);
  if(hProcess==NULL){return -20;}
  //分配内存:
  pDll=::VirtualAllocEx(hProcess,NULL,strlen(dllpath),MEM_COMMIT,PAGE_READWRITE);
  if(pDll==NULL){return -21;}
  //注入DLL:
  BOOL bRe=::WriteProcessMemory(hProcess,pDll,(void*)dllpath,strlen(dllpath),NULL);
  if(bRe==FALSE){return -22;}
  //获取LoadLibraryA函数地址:
  FARPROC pLoadDll=GetProcAddress(GetModuleHandle("kernel32.dll"),"LoadLibraryA");
  if(pLoadDll==NULL){return -23;}
  //创建线程:
  HANDLE hRemote=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pLoadDll,pDll,NULL,0);
  //等待线程结束:
  ::WaitForSingleObject(hRemote,INFINITE);
  if(hRemote!=NULL){::CloseHandle(hRemote);}
  if(hProcess!=NULL){::CloseHandle(hProcess);}
  return 0;
  }
  //注入给指定程序句柄的进程:
  int CRemoteShell::Load(LPCTSTR dllpath,HWND hWnd)
  {
  hProcess =NULL;
  pDll =NULL;
  pId =NULL;
  m_dllPath =dllpath;
  if(hWnd!=NULL){::GetWindowThreadProcessId(hWnd,&pId);}
  //如果指定进程ID为NULL,就注入给自己.
  if(pId==NULL){pId=::GetCurrentProcessId();}
  //打开进程:
  hProcess=::OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,1,pId);
  if(hProcess==NULL){return -20;}
  //分配内存:
  pDll=::VirtualAllocEx(hProcess,NULL,strlen(dllpath),MEM_COMMIT,PAGE_READWRITE);
  if(pDll==NULL){return -21;}
  //注入DLL:
  BOOL bRe=::WriteProcessMemory(hProcess,pDll,(void*)dllpath,strlen(dllpath),NULL);
  if(bRe==FALSE){return -22;}
  //获取LoadLibraryA函数地址:
  FARPROC pLoadDll=::GetProcAddress(::GetModuleHandle("kernel32.dll"),"LoadLibraryA");
  if(pLoadDll==NULL){return -23;}
  //创建线程:
  HANDLE hRemote=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)pLoadDll,pDll,NULL,0);
  //等待线程结束:
  ::WaitForSingleObject(hRemote,INFINITE);
  hDll=GetDllHandle(dllpath,pId);
  if(hRemote!=NULL){::CloseHandle(hRemote);}
  if(hProcess!=NULL){::CloseHandle(hProcess);}
  return 0;
  }
  int CRemoteShell::Release(DWORD procId)
  {
  DWORD id=NULL;
  if(hDll==NULL){return -1;}
  if(pId!=NULL){id=pId;}
  if(procId!=NULL){id=procId;}
  if(id!=NULL){
  //打开进程:
  hProcess=::OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_WRITE|PROCESS_VM_OPERATION,1,pId);
  if(hProcess==NULL){return -20;}
  //FARPROC pGetDllHandle=GetProcAddress(GetModuleHandle("ntdll.dll"),"LdrGetDllHandle");
  //获取FreeLibraryA函数地址:
  FARPROC pFreeDll=GetProcAddress(GetModuleHandle("kernel32.dll"),"FreeLibrary");
  if(pFreeDll==NULL){return -23;}
  //创建线程:
  HANDLE hRemote=::CreateRemoteThread(hProcess,NULL,0,
  (LPTHREAD_START_ROUTINE)
  pFreeDll,hDll,NULL,0);
  //等待线程结束:
  ::WaitForSingleObject(hRemote,INFINITE);
  ::VirtualFreeEx(hProcess,pDll,0,MEM_RELEASE);
  if(hRemote!=NULL){::CloseHandle(hRemote);}
  if(hProcess!=NULL){::CloseHandle(hProcess);}
  }else{AfxMessageBox("进程号为空!无法释放!");}
  return 0;
  }
  HANDLE CRemoteShell::GetDllHandle(LPCTSTR path,DWORD pid)
  {
  if(pid==NULL){pid=::GetCurrentProcessId();}
  //打开进程:
  int num=0;
  BOOL bRe=FALSE;
  HANDLE hModule=NULL;
  MODULEENTRY32* minfo=NULL;
  minfo=new MODULEENTRY32;
  if(NULL!=pid)
  {
  hModule=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,pid);
  bRe=Module32First(hModule, minfo);
  for(;bRe!=0;num++)
  {
  if(lstrcmp(minfo->szExePath,path)==0||lstrcmp(minfo->szModule,path)==0)
  {return minfo->modBaseAddr;}
  bRe=::Module32Next(hModule,minfo);
  }
  }
  if(minfo!=NULL){delete minfo;}
  ::CloseHandle(hModule);
  return NULL;
  }
  //----------------------------------------------------------------------------------------------
  我们用上面的类就可以轻松的把一个DLL注入到别的进程,并且还可以轻松的释放。做到不知不觉。
  话归前题,我们要怎么样才能对CallWindowProc这个API做手脚了。可以看到这个函数的入口地方很简单:
  //-------------------------------------------------------------
  77D1E8EA > 8BFF mov edi, edi
  77D1E8EC 55 push ebp
  77D1E8ED 8BEC mov ebp, esp
  77D1E8EF 6A 01 push 1 ;只是和前面不一样多了个参数1
  77D1E8F1 FF75 18 push dword ptr [ebp+18]
  77D1E8F4 FF75 14 push dword ptr [ebp+14]
  77D1E8F7 FF75 10 push dword ptr [ebp+10]
  77D1E8FA FF75 0C push dword ptr [ebp+C]
  77D1E8FD FF75 08 push dword ptr [ebp+8]
  77D1E900 E8 E9DCFFFF call 77D1C5EE
  77D1E905 5D pop ebp
  77D1E906 C2 1400 retn 14
  //-----------------------------------------------------------------------
  我们定义了一个函数类型:
  typedef LRESULT (*CALLPROC)(WNDPROC,HWND,UINT,WPARAM,LPARAM,int);
  这样我们就可以轻松的调用这个函数了。
  我们只需要把:
  77D1E900 E8 E9DCFFFF call 77D1C5EE
  改为我们自己的就可以了。
  分析好以后,我们就在我们准备好的DLL中加入我们代替它的回调函数:
  //----------------------------------------------------------------------------------------------------
  LRESULT CALLBACK pnCallWindowProc(IN WNDPROC lpPrevWndFunc,
  IN HWND hWnd,IN UINT Msg,
  IN WPARAM wParam,IN LPARAM lParam,IN int unk)
  {
  switch(Msg)
  {
  case WM_CMD_EXIT:
  { //这里是我们自己定义给进程的命令,也就是自定义消息:
  AfxMessageBox("获取到命令");return TRUE;
  }
  default:{break;}
  }
  //返回到原来的地址:
  return lpSrcCallProc(lpPrevWndFunc,hWnd,Msg,wParam,lParam,unk);
  }
  //-------------------------------------------------------------------------------------------------------
  我们在DLL加载时,把上面那个地方改掉就可以了。
  //----------------------------------------------------------------------------------------------
  void CMyRemoteDllApp::SetHookApiCallBack()
  {
  //获取回调函数地址:
  hModule=::GetModuleHandle("User32.dll");
  FARPROC fpCallWindowProc=::GetProcAddress(hModule,"CallWindowProcA");
  //这里需要做说明了,最好大家不要用虚拟绝对地址,建议用虚拟相对地址,这样即使user32.dll的版本不一样
  //也不会影响到我们的DLL,我这里都是通过计算得到的。
  //声明结构对象,为了方便修改,我写了个结构来处理:
  _ASM_CALL _call;
  _call._01cmd =0xE8;
  DWORD dword=(DWORD)&pnCallWindowProc-((DWORD)fpCallWindowProc+0x16)-5;
  memcpy((PDWORD)_call._02dat,&dword,4);
  //获取当前内存块的保护类型,由于是系统DLL只给R的权限,我们必须把R改成RW才能把我们的函数替换进去:
  MEMORY_BASIC_INFORMATION _base;
  ::VirtualQuery((LPVOID)((DWORD)hModule+0x1000),&_base,sizeof(MEMORY_BASIC_INFORMATION));
  //保存原始入口地址,我们处理的是自定义消息,我们不需要处理全部,所以其他的都转给原来的地址:
  //做到这里就想起病毒~~~,所以再三请大家不要用于它途
  lpSrcCallProc=(CALLPROC)(*(PDWORD)((DWORD)fpCallWindowProc+0x17));
  lpSrcCallProc=(CALLPROC)((DWORD)fpCallWindowProc+0x16+(DWORD)lpSrcCallProc+5);
  //处理为读写类型:
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,PAGE_READWRITE,&_base.Protect);
  memcpy((LPVOID)((DWORD)fpCallWindowProc+0x16),&_call,5);
  //处理完成后,恢复保护类型:
  DWORD dwProctect=NULL;
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,_base.Protect,&dwProctect);
  }
  //-------------------------------------------------------------------------------------------------------
  只加载不算完啊,我们要在DLL退出前把它再改回来的,要不程序会不正常的。
  //-----------------------------------------------------------------------------------------
  int CMyRemoteDllApp::ExitInstance()
  {
  // TODO: Add your specialized code here and/or call the base class
  //获取回调函数地址:
  hModule=::GetModuleHandle("User32.dll");
  FARPROC fpCallWindowProc=::GetProcAddress(hModule,"CallWindowProcA");
  //获取当前内存块的保护类型:
  MEMORY_BASIC_INFORMATION _base;
  ::VirtualQuery((LPVOID)((DWORD)hModule+0x1000),&_base,sizeof(MEMORY_BASIC_INFORMATION));
  DWORD dword=(DWORD)lpSrcCallProc-((DWORD)fpCallWindowProc+0x16)-5;
  //声明结构对象:
  _ASM_CALL _call;
  _call._01cmd =0xE8;
  memcpy((PDWORD)_call._02dat,&dword,4);
  //处理为读写类型:
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,PAGE_READWRITE,&_base.Protect);
  memcpy((LPVOID)((DWORD)fpCallWindowProc+0x16),&_call,5);
  //处理完成后,恢复保护类型:
  DWORD dwProctect=NULL;
  ::VirtualProtect(_base.BaseAddress,_base.RegionSize,_base.Protect,&dwProctect);
  return CWinApp::ExitInstance();
  }
  //-----------------------------------------------------------------------------------------
  在回调函数前必须加 CALLBACK,请大家要注意了,因为加与不加在汇编语言里是完全不一样的:
  //加了的:
  //---------------------------------------------------------------------------------------------
  1000129C 55 push ebp
  1000129D 8BEC mov ebp, esp
  1000129F 51 push ecx
  100012A0 8B45 10 mov eax, dword ptr [ebp+10]
  100012A3 8945 FC mov dword ptr [ebp-4], eax
  100012A6 817D FC 6404000>cmp dword ptr [ebp-4], 464
  100012AD 74 02 je short 100012B1
  100012AF EB 15 jmp short 100012C6
  100012B1 6A 00 push 0
  100012B3 6A 00 push 0
  100012B5 68 64300010 push 10003064
  100012BA E8 A7010000 call 10001466 ; jmp 到 MFC42.#1200
  100012BF B8 01000000 mov eax, 1
  100012C4 EB 21 jmp short 100012E7
  100012C6 8B4D 1C mov ecx, dword ptr [ebp+1C]
  100012C9 51 push ecx
  100012CA 8B55 18 mov edx, dword ptr [ebp+18]
  100012CD 52 push edx
  100012CE 8B45 14 mov eax, dword ptr [ebp+14]
  100012D1 50 push eax
  100012D2 8B4D 10 mov ecx, dword ptr [ebp+10]
  100012D5 51 push ecx
  100012D6 8B55 0C mov edx, dword ptr [ebp+C]
  100012D9 52 push edx
  100012DA 8B45 08 mov eax, dword ptr [ebp+8]
  100012DD 50 push eax
  100012DE FF15 D4310010 call dword ptr [100031D4] ; USER32.77D1C5EE
  100012E4 83C4 18 add esp, 18
  100012E7 8BE5 mov esp, ebp
  100012E9 5D pop ebp
  100012EA C2 1800 retn 18
  //---------------------------------------------------------------------------------------------
  没加的,类似如下,没加会在堆栈溢出,必须手动修改ESP,才能正常:
  //-------------------------------------------------------------------------------------------------
  100017A1 55 push ebp
  100017A2 8BEC mov ebp, esp
  100017A4 53 push ebx
  ……
  10001831 8945 0C mov dword ptr [ebp+C], eax
  10001834 8B45 0C mov eax, dword ptr [ebp+C]
  10001837 5F pop edi
  10001838 5E pop esi
  10001839 5B pop ebx
  1000183A 5D pop ebp
  1000183B C2 0C00 retn 0C
  //--------------------------------------------------------------------------------------------------
  再需要说明一下:
  Call 地址不是实际地址是要算的哦
  目的地址-当前地址-5
  就是CALL 的值,这个是个简单点的公式!!!大家用的着哦!
  如果,大家要是在,DLL中加入了窃取信息的代码,那么它就是个木马了,只要发个消息它就工作,或者设定在收到某个消息后才工作,我想要比那些网上的木马高明点,但是我还希望大家不要这么做,因为,这样做的后果是可怜的哦。还有就是不要拿系统进程做实验,容易死机。
  好了,到现在我们所做的就完工了,还算是基本完美吧!大家发给消息给被注入进程,可以看到有提示。
  大家自己做的时候要注意了,用完HANDLE别忘记CloseHandle,这个习惯也注意了哦~~~程序的稳定,很重要的点滴..
  调用的时候想法子,不让卡巴发现!比如,从API的中途调用,API的头和尾我自己来写,毕竟,卡巴不可能将ntdll.dll中的所有跨进程操作的API的挂掉,实际,能做到这个方法有很多~~~~~除非,卡巴对所有API的所有代码都监视,那样就无语了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值