远程线程入门

  远程线程作为一项"合法"的代码注入技术,在windows上被大量使用, 它的本质就是把一块可执行代码写入到对方进程,然后让其起运行起来。

      一般它的实现过程是这样的, 通过VirtualAllocEx在目标进程分配内存空间,然后通过WriteProcessMemory将我们的可执行代码写入到目标进程,最后通过CreateRemoteThread让我们的可执行代码在目标进程里运行起来。

     一般实现远程线程有2种方法, 一种是《windows核心编程》里介绍的,通过线程函数和LoadLibrary API函数申明的相似性, 直接在目标进程里调用LoadLibrary加载我们DLL,这样我们只要在DLL_PROCESS_ATTACH里执行我们的代码就可以了。代码如下, 通过InjectLib在目标进程加载我们的DLL, 通过EjectLib卸载我们的DLL:

 

///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI InjectLibW(DWORD dwProcessId, PCWSTR pszLibFile) 
{

   BOOL fOk = FALSE; // Assume that the function fails
   HANDLE hProcess = NULL, hThread = NULL;
   PWSTR pszLibFileRemote = NULL;

   __try {
      // Get a handle for the target process.
      hProcess = OpenProcess(
         PROCESS_QUERY_INFORMATION |   // Required by Alpha
         PROCESS_CREATE_THREAD     |   // For CreateRemoteThread
         PROCESS_VM_OPERATION      |   // For VirtualAllocEx/VirtualFreeEx
         PROCESS_VM_WRITE,             // For WriteProcessMemory
         FALSE, dwProcessId);
      if (hProcess == NULL)
      {
          __leave;
      }

      // Calculate the number of bytes needed for the DLL's pathname
      int cch = 1 + lstrlenW(pszLibFile);
      int cb  = cch * sizeof(WCHAR);

      // Allocate space in the remote process for the pathname
      pszLibFileRemote = (PWSTR) 
         VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
      if (pszLibFileRemote == NULL)
      {      
         __leave;
      }

      // Copy the DLL's pathname to the remote process's address space
      if (!WriteProcessMemory(hProcess, pszLibFileRemote, 
         (PVOID) pszLibFile, cb, NULL))
      {      
         __leave;
      }

      // Get the real address of LoadLibraryW in Kernel32.dll
      PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
         GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");
      if (pfnThreadRtn == NULL)
      {
          __leave;
      }

      // Create a remote thread that calls LoadLibraryW(DLLPathname)
      hThread = CreateRemoteThread(hProcess, NULL, 0, 
         pfnThreadRtn, pszLibFileRemote, 0, NULL);
      if (hThread == NULL)
      {
         __leave;
      }

      // Wait for the remote thread to terminate
      WaitForSingleObject(hThread, INFINITE);

      fOk = TRUE; // Everything executed successfully
   }
   __finally { // Now, we can clean everthing up

      // Free the remote memory that contained the DLL's pathname
      if (pszLibFileRemote != NULL) 
         VirtualFreeEx(hProcess, pszLibFileRemote, 0, MEM_RELEASE);

      if (hThread  != NULL) 
         CloseHandle(hThread);

      if (hProcess != NULL) 
         CloseHandle(hProcess);
   }

   return(fOk);
}

///////////////////////////////////////////////////////////////////////////////

BOOL WINAPI InjectLibA(DWORD dwProcessId, PCSTR pszLibFile) 
{

   // Allocate a (stack) buffer for the Unicode version of the pathname
   PWSTR pszLibFileW = (PWSTR) 
      _alloca((lstrlenA(pszLibFile) + 1) * sizeof(WCHAR));

   // Convert the ANSI pathname to its Unicode equivalent
   wsprintfW(pszLibFileW, L"%S", pszLibFile);

   // Call the Unicode version of the function to actually do the work.
   return(InjectLibW(dwProcessId, pszLibFileW));
}

///////////////////////////////////////////////////////////////////////////////

BOOL WINAPI EjectLibW(DWORD dwProcessId, PCWSTR pszLibFile) 
{

   BOOL fOk = FALSE; // Assume that the function fails
   HANDLE hthSnapshot = NULL;
   HANDLE hProcess = NULL, hThread = NULL;

   __try {
      // Grab a new snapshot of the process
      hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
      if (hthSnapshot == INVALID_HANDLE_VALUE)
      {
         __leave;
      }

      // Get the HMODULE of the desired library
      MODULEENTRY32W me = { sizeof(me) };
      BOOL fFound = FALSE;
      BOOL fMoreMods = Module32FirstW(hthSnapshot, &me);
      for (; fMoreMods; fMoreMods = Module32NextW(hthSnapshot, &me)) {
         fFound = (lstrcmpiW(me.szModule,  pszLibFile) == 0) || 
                  (lstrcmpiW(me.szExePath, pszLibFile) == 0);
         if (fFound) break;
      }
      if (!fFound)
      {
         __leave;
      }

      // Get a handle for the target process.
      hProcess = OpenProcess(
         PROCESS_QUERY_INFORMATION |   // Required by Alpha
         PROCESS_CREATE_THREAD     | 
         PROCESS_VM_OPERATION,  // For CreateRemoteThread
         FALSE, dwProcessId);
      if (hProcess == NULL)
      {    
         __leave;
      }

      // Get the real address of LoadLibraryW in Kernel32.dll
      PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
         GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
      if (pfnThreadRtn == NULL)
      {
         __leave;
      }

      // Create a remote thread that calls LoadLibraryW(DLLPathname)
      hThread = CreateRemoteThread(hProcess, NULL, 0, 
         pfnThreadRtn, me.modBaseAddr, 0, NULL);
      if (hThread == NULL)
      {
         __leave;
      }

      // Wait for the remote thread to terminate
      WaitForSingleObject(hThread, INFINITE);

      fOk = TRUE; // Everything executed successfully
   }
   __finally { // Now we can clean everything up

      if (hthSnapshot != NULL) 
         CloseHandle(hthSnapshot);

      if (hThread     != NULL) 
         CloseHandle(hThread);

      if (hProcess    != NULL) 
         CloseHandle(hProcess);
   }

   return(fOk);
}

///////////////////////////////////////////////////////////////////////////////

BOOL WINAPI EjectLibA(DWORD dwProcessId, PCSTR pszLibFile)
{

   // Allocate a (stack) buffer for the Unicode version of the pathname
   PWSTR pszLibFileW = (PWSTR) 
      _alloca((lstrlenA(pszLibFile) + 1) * sizeof(WCHAR));

   // Convert the ANSI pathname to its Unicode equivalent
   wsprintfW(pszLibFileW, L"%S", pszLibFile);

   // Call the Unicode version of the function to actually do the work.
   return(EjectLibW(dwProcessId, pszLibFileW));
}

///////////////////////////////////////////////////////////////////////////////

 上面这种方法注入的代码它的优点是开发比较简单,我们只要用C++写一个DLL,然后调用InjectLibW(processID, dllName)就可以了,但是因为代码是运行在一个DLL里,别人可以通过一些枚举模块的工具看到我们的DLL,所以隐蔽性不是很好。

      还有一种远程线程的实现方法是罗云彬《Windows环境下32位汇编语言程序设计》里介绍的,
我们不通过DLL,而是直接把可执行代码拷贝到目标进程后运行,所以它是真正的远程线程,通过这种方法,我们的代码和目标进程已经完全融为一体,其他人根本无法察觉。

      用这种方法实现, 它的要点是:

      (1) Kernel32.DLL加载的基址在任何进程里都是一样的(其实上一种LoadLibrary方法也用到了这点), 所以GetProcAddress,GetModuleHandleA(W), LoadLibraryA(W)这些API的地址在任何进程里都是一样的, 所以我们在其他进程中用和本进程相同的地址调用这些API。

    (2) 因为涉及到全局变量的重定位问题, 所以注入的代码需要用汇编编写, 并用以下汇编解决重定位问题

时间: 2024-09-22 21:14:16

远程线程入门的相关文章

C#实现远程线程插入

使用.NET可以实现远程线程插入吗? 使用严格的C#,不借助任何其它技术.远程线程插入是不能在.NET平台上实现的.然而在shellcode技术和远程线程插入之代码插入的基础上.完全可以实现基于.NET平台的混合型远程线程插入. 最终效果是这样的:用于将线程插入到其它进程的可执行程序是.NET程序(混合几百字节的机器码),用于被插入到其它进程的DLL或EXE也是纯.NET实现的. 可被插入的对象是所有有权限进程WriteProcessMemory操作的本机进程. 实现C#下的远程线程插入需要的技

关于远程线程加载dll释放的问题

问题描述 关于远程线程加载dll释放的问题 有下面的代码: ''' EnablePrivilege(SE_DEBUG_NAME, TRUE); hprocess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processid); char buff[] = "Win32Project2.dll"; PSTR chRemote = NULL; chRemote = (PSTR)VirtualAllocEx(hprocess, NULL, lstrle

远程线程注入引出的问题

远程线程注入引出的问题   一.远程线程注入基本原理 远程线程注入--相信对Windows底层编程和系统安全熟悉的人并不陌生,其主要核心在于一个Windows API函数CreateRemoteThread,通过它可以在另外一个进程中注入一个线程并执行.在提供便利的同时,正是因为如此,使得系统内部出现了安全隐患.常用的注入手段有两种:一种是远程的dll的注入,另一种是远程代码的注入.后者相对起来更加隐蔽,也更难被杀软检测.本文具体实现这两种操作,在介绍相关API使用的同时,也会解决由此引发的一些

Java线程入门——定义线程中的 run 方法

run 方法是运行线程时需要执行的代码.(你要用代码--也就是 run() 方法--来描述一个处理过程,而不是创建一个表示这个处理过程的对象.在如何理解线程方面,一直存在着争议.这取决于,你是将线程看作是对象还是处理过程.如果你认为它是一个处理过程,那么你就摆脱了"万物皆对象"的 OO 教条.但与此同时,如果你只想让这个处理过程掌管程序的某一部分,那你就没理由让整个类都成为 Runnable 的.有鉴于此,用内部类的形式将线程代码隐藏起来,通常是个更明智的选择.来自TIJ3.) 在 J

线程入门-线程同步浅析

前言 刚实习的时候,当遇到数据量大并对效率要求高的业务时,就开始尝试学习如何使用多线程来处理.现在与大家分享一下.大家说到多线程,总有一个绕不开的问题,就是如何实现多线程的同步.大致总结了2个大家常用的方式:synchronized关键字与java.util.concurrent.locks.Lock接口. synchronized关键字 synchronized关键字一般作用于代码块或者方法.根据场景又有所不同. synchronized作用于代码块时 synchronized(this) 这

详情Python编写shellcode注入程序入门教程

背景 本文为入门基础,纯科普,大牛莫喷~ 教程中所有内容仅供学习研究,请勿用于非法用途,否则....我也帮不了你啊... 说起注入,大家第一印象可能还习惯性的停留在sql注入,脚本注入(XSS)等.今天light同(jiao)学(shou)带大家从web端回到操作系统,一起探讨Windows下的经典注入--内存注入,使用python编写一个简单的代码注入程序. 内存注入常见的方法有dll注入和代码注入.Dll注入通俗地讲就是把我们自己的dll注入到目标进程的地址空间内,"寄生"在目标进

浅析三线程程序开发思路与实现

一.前言 中国黑客(worm.runouce)病毒在国内出现以后,各大反病毒公司都对其进行了"仔细"的分析,得出一个结论:"中国黑客"发现了全球首创的"三线程"结构.这是某公司对外的宣传词,我个人对病毒没什么研究,并且我对worm.runouce没有任何的个人看法,不过我可以确信的是很多反病毒公司往往在夸大事实,目的只有一个:让更多的用户觉得某某病毒很可怕,让更多的用户相信只有某某公司的杀毒软件才可以彻底将病毒清除掉.其实三线程并没有好高深的技术

C#线程专题

C#中线程与窗体交互的多线程编程实例 C#并行编程概述:线程同步原语 C#中Queue的线程安全问题 C#编程总结(五)关于多线的思考 C#编程总结(四)多线程应用 C#编程总结(三)线程同步 C#编程总结(二)多线程基础 C#实现的多线程异步Socket数据包接收器框架 C#.net同步异步SOCKET通讯和多线程总结 大量数据转录的多线程和同步处理实现 c#中使用多线程访问winform中控件的若干问题 一个简单的多线程即时通讯程序(类似QQ,MSN) C#中跨线程操作控件 C#多线程del

32位程序对64位进程的远程注入实现

本文讲的是32位程序对64位进程的远程注入实现, 0x00 前言 要对指定进程进行远程注入,通常使用Windows提供的API CreateRemoteThread创建一个远程线程,进而注入dll或是执行shellcode. 在64位系统下,该方法需要特别注意,注入的目标进程要同程序的结构保持一致,即32位程序只能对32进程作注入,64位程序只能对64位进程作注入,32位程序对64位程序进行注入时会失败(32位和64位的结构不同). 然而,在某些特殊的环境下,无法提前预知目标进程的结构,准备两个