怎樣實(shí)現(xiàn).net程序的進(jìn)程注入_.Net教程

      編輯Tag賺U幣
      教程Tag:暫無(wú)Tag,歡迎添加,賺取U幣!

      推薦:如何在.NET環(huán)境下為網(wǎng)站增加IP過(guò)濾功能
      華能集團(tuán)下某發(fā)電廠的企業(yè)網(wǎng)站(基于Asp.Net2.0實(shí)現(xiàn),不允許修改源程序)要求實(shí)現(xiàn)廠內(nèi)用戶可直接訪問(wèn)整個(gè)站點(diǎn)的所有頁(yè)面,廠外用戶只能訪問(wèn)指定的頁(yè)面的功能,本文將按照需求分析、方案設(shè)計(jì)、編碼實(shí)現(xiàn)、部署應(yīng)用的順序逐步闡述整個(gè)解決方案的形成過(guò)程。 1.

      進(jìn)程注入比較常見(jiàn),比如用IDE調(diào)試程序以及一些Spy程序,如果僅僅為了與調(diào)試器通訊,可以使用.net提供的Debugger接口(在EnvDTE.dll的EnvDTE命名空間下).但無(wú)論出于什么目的,進(jìn)程注入都是比較好玩的事情,所以不妨一試 . 進(jìn)程注入的方法貌似很多(比如像特洛伊一樣喬裝打扮讓目標(biāo)進(jìn)程誤認(rèn)為你的程序集合法而加載到目標(biāo)進(jìn)程),這里提到的僅是其中的一種或某些方法的結(jié)合.

        大致原理是這樣的:

        源進(jìn)程(也就是你的代碼所在的進(jìn)程)獲得目標(biāo)進(jìn)程(也就是你的注入目標(biāo)所在的進(jìn)程)的ID或進(jìn)程對(duì)象

        源進(jìn)程提供一回調(diào)函數(shù)methodA(也就是你想要注入到目標(biāo)進(jìn)程后所執(zhí)行的代碼)

        將目標(biāo)進(jìn)程和回調(diào)函數(shù)methodA的完整路徑(其所在的Assembly,Classic以及MethodName)提交給Injector(也就是我們編寫(xiě)的負(fù)責(zé)注入的類),讓Injector來(lái)完成注入和讓目標(biāo)進(jìn)程執(zhí)行回調(diào)函數(shù)

        Injector根據(jù)提供的目標(biāo)進(jìn)程ID取得目標(biāo)進(jìn)程對(duì)象,并獲得目標(biāo)進(jìn)程的一個(gè)線程(我們稱為目標(biāo)線程)

        在目標(biāo)線程中分配一塊內(nèi)存,將回調(diào)函數(shù)methodA的完整路徑作為字符串存入該內(nèi)存中

        Injector在目標(biāo)進(jìn)程中安裝一個(gè)鉤子(Hook)監(jiān)視某一個(gè)Windows消息(messageA),撰寫(xiě)鉤子的回調(diào)函數(shù)methodB(該方法中的內(nèi)容稍后解釋)

        像目標(biāo)進(jìn)程發(fā)消息messageA,并將剛才分配的內(nèi)存的基地址作為消息參數(shù)傳遞.

        由于我們針對(duì)messageA安裝了鉤子,所以目標(biāo)進(jìn)程會(huì)調(diào)用我們鉤子函數(shù)methodB,并會(huì)把分配的內(nèi)存的基地址包含在函數(shù)參數(shù)中

        methodB中, 根據(jù)函數(shù)參數(shù)中的內(nèi)存基地址在內(nèi)存中解析出其實(shí)際對(duì)象,也就是一個(gè)表示我們的methodA的完整路徑的字符串.根據(jù)該字符串中所表示的Assembly,className, methodName利用.net反射,反射出其MethodInfo對(duì)象(注意,關(guān)鍵點(diǎn),methodB被回調(diào)時(shí)已經(jīng)是在目標(biāo)進(jìn)程的某個(gè)線程中了) Invoke反射出的MethodInfo對(duì)象, 我們的methodA得到了執(zhí)行.

        下面這個(gè)圖可能會(huì)幫助你理解上面的話: 

      如何實(shí)現(xiàn).net程序的進(jìn)程注入

          圖片看不清楚?請(qǐng)點(diǎn)擊這里查看原圖(大圖)。

        如果還沒(méi)明白的話,那就看代碼吧(這需要一點(diǎn)點(diǎn)C++/CLI知識(shí),但我已經(jīng)為每句加上了注釋,應(yīng)該蠻好懂的,C++/CLI可以點(diǎn)擊這里了解更多.關(guān)于ManagedInjector可以點(diǎn)擊這里了解更多)

      #include "stdafx.h"
      #include "Injector.h"
      #include <vcclr.h>
      using namespace ManagedInjector;
      //defines a new window message that is guaranteed to be unique throughout the system.
      //The message value can be used when sending or posting messages.
      static unsigned int WM_GOBABYGO = ::RegisterWindowMessage(L"Injector_GOBABYGO!");
      static HHOOK _messageHookHandle;
      //-----------------------------------------------------------------------------
      //Spying Process functions follow
      //-----------------------------------------------------------------------------
      void Injector::Launch(System::IntPtr windowHandle, System::Reflection::Assembly^ assembly, System::String^ className, System::String^ methodName) {
          System::String^ assemblyClassAndMethod = assembly->Location + "$" + className + "$" + methodName;
          //convert String to local wchar_t* or char*
          pin_ptr<const wchar_t> acmLocal = PtrToStringChars(assemblyClassAndMethod);
          //Maps the specified executable module into the address space of the calling process.
          HINSTANCE hinstDLL = ::LoadLibrary((LPCTSTR) _T("ManagedInjector.dll"));
          if (hinstDLL)
          {
              DWORD processID = 0;
              //get the process id and thread id
              DWORD threadID = ::GetWindowThreadProcessId((HWND)windowHandle.ToPointer(), &processID);
              if (processID)
              {
                  //get the target process object (handle)
                  HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
                  if (hProcess)
                  {
                      int buffLen = (assemblyClassAndMethod->Length + 1) * sizeof(wchar_t);
                      //Allocates physical storage in memory or in the paging file on disk for the specified reserved memory pages.
                      //The function initializes the memory to zero.
                      //The return value is the base address of the allocated region of pages.
                      void* acmRemote = ::VirtualAllocEx(hProcess, NULL, buffLen, MEM_COMMIT, PAGE_READWRITE);
                      if (acmRemote)
                      {
                          //copies the data(the assemblyClassAndMethod string)
                          //from the specified buffer in the current process
                          //to the address range of the target process
                          ::WriteProcessMemory(hProcess, acmRemote, acmLocal, buffLen, NULL);
                     
                          //Retrieves the address of MessageHookProc method from the hintsDLL
                          HOOKPROC procAddress = (HOOKPROC)GetProcAddress(hinstDLL, "MessageHookProc");
                          //install a hook procedure to the target thread(before the system sends the messages to the destination window procedure)
                          _messageHookHandle = ::SetWindowsHookEx(WH_CALLWNDPROC, procAddress, hinstDLL, threadID);
                          if (_messageHookHandle)
                          {
                              //send our custom message to the target window of the target process
                              ::SendMessage((HWND)windowHandle.ToPointer(), WM_GOBABYGO, (WPARAM)acmRemote, 0);
                              //removes the hook procedure installed in a hook chain by the SetWindowsHookEx function.
                              ::UnhookWindowsHookEx(_messageHookHandle);
                          }
                          //removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.
                          ::VirtualFreeEx(hProcess, acmRemote, buffLen, MEM_RELEASE);
                      }
                      ::CloseHandle(hProcess);
                  }
              }
              //Decrements the reference count of the loaded DLL
              ::FreeLibrary(hinstDLL);
          }
      }
      __declspec( dllexport )
      // The procedure for hooking, this will be called back after hooked
      int __stdcall MessageHookProc(int nCode, WPARAM wparam, LPARAM lparam) {
          //HC_ACTION: indicate that there are argments in wparam and lparam
          if (nCode == HC_ACTION)
          {
              CWPSTRUCT* msg = (CWPSTRUCT*)lparam;
              //when the target window received our custom message
              if (msg != NULL && msg->message == WM_GOBABYGO)
              {
                  //get the argument passed by the message
                  //actually, the argument is the base address (a pointer)
                  //of the assemblyClassAndMethod string in the target process memory
                  wchar_t* acmRemote = (wchar_t*)msg->wParam;
                  //gcnew: creates an instance of a managed type (reference or value type) on the garbage collected heap
                  System::String^ acmLocal = gcnew System::String(acmRemote);
                  //split the string into substring array with $. Under this context:
                  //acmSplit[0]:the assembly's location
                  //acmSplit[1]:className;
                  //acmSplit[2]:methodName
                  //we use these infomation to reflect the method in the source assembly, and invoke it in the target process
                  cli::array<System::String^>^ acmSplit = acmLocal->Split('$');
                  //refect the method, and invoke it
                  System::Reflection::Assembly^ assembly = System::Reflection::Assembly::LoadFile(acmSplit[0]);
                  if (assembly != nullptr)
                  {
                      System::Type^ type = assembly->GetType(acmSplit[1]);
                      if (type != nullptr)
                      {
                          System::Reflection::MethodInfo^ methodInfo =
                              type->GetMethod(acmSplit[2], System::Reflection::BindingFlags::Static | System::Reflection::BindingFlags::Public);
                          if (methodInfo != nullptr)
                          {
                              methodInfo->Invoke(nullptr, nullptr);
                          }
                      }
                  }
              }
          }
          return CallNextHookEx(_messageHookHandle, nCode, wparam, lparam);
      }接下來(lái),做個(gè)DEMO嘗試一下: 

      如何實(shí)現(xiàn).net程序的進(jìn)程注入  

        解決方案中的InjectorDemo就是我們上述的源進(jìn)程,它會(huì)利用Injector將下面這段代碼注入到Target進(jìn)程中并執(zhí)行:

      public static void DoSomethingEvie()
      {
          vartargetWindow = Application.Current.MainWindow;

          if(targetWindow != null)
          {
              varlb = newLabel{Content = "haha, i caught you :)"};
              targetWindow.Content = lb;
          }
      }

        也就是說(shuō)InjectorDemo進(jìn)程會(huì)將InjectTargetApp進(jìn)程的主窗口的內(nèi)容修改成"haha, i caught you"這樣的一個(gè)Label.

        運(yùn)行程序: 

         如何實(shí)現(xiàn).net程序的進(jìn)程注入

          圖片看不清楚?請(qǐng)點(diǎn)擊這里查看原圖(大圖)。 

        上面的兩個(gè)窗口分別處于不同的進(jìn)程中, 點(diǎn)擊 "Inject it" 按鈕, 其輝調(diào)用如下代碼:

      ManagedInjector.Injector.Launch(targetProcess.MainWindowHandle, typeof(InjectorWindow).Assembly, typeof(InjectorWindow).FullName, "DoSomethingEvie");

        然后:

      如何實(shí)現(xiàn).net程序的進(jìn)程注入

       

          圖片看不清楚?請(qǐng)點(diǎn)擊這里查看原圖(大圖)。 

      分享:淺談使用ASP.NET Global.asax 文件
      Global.asax文件,有時(shí)候叫做ASP.NET應(yīng)用程序文件,提供了一種在一個(gè)中心位置響應(yīng)應(yīng)用程序級(jí)或模塊級(jí)事件的方法。你可以使用這個(gè)文件實(shí)現(xiàn)應(yīng)用程序安全性以及其它一些任務(wù)。下面讓我們?cè)敿?xì)看一下如何在應(yīng)用程序開(kāi)發(fā)工作中使用這個(gè)文件。 概述 Global.asax位于

      來(lái)源:模板無(wú)憂//所屬分類:.Net教程/更新時(shí)間:2009-07-08
      相關(guān).Net教程