实战DELPHI:远程线程插入(DLL注入)

http://www.jx19.com/xxzl/Delphi/2010/04/17/ShiZhanDELPHI_YuanChengXianChengChaRu_DLLZhuRu/

远程注入DLL方法有很多种,也是很多木马病毒所使用的隐藏进程的方法,因为通过程序加载的DLL在进程管理器是没有显示的.这里介绍一种用 CreateRemoteThread 远程建立线程的方式注入DLL.

首先,我们要提升自己的权限,因为远程注入必不可免的要访问到目标进程的内存空间,如果没有足够的系统权限,将无法作任何事.下面是这个函数是用来提升我们想要的权限用的.

function EnableDebugPriv: Boolean;
var
  hToken: THandle;
  tp: TTokenPrivileges;
  rl: Cardinal;
begin
  Result := false;

//打开进程令牌环
  OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,
    hToken);

//获得进程本地唯一ID
  if LookupPrivilegeValue(nil, ‘SeDebugPrivilege‘, tp.Privileges[0].Luid) then
  begin
    tp.PrivilegeCount           := 1;
    tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
    //调整权限
    Result := AdjustTokenPrivileges(hToken, false, tp, SizeOf(tp), nil, rl);
  end;
end;

关于 OpenProcessToken() 和 AdjustTokenPrivileges() 两个 API 的简单介绍:

OpenProcessToken():获得进程访问令牌的句柄.
  function OpenProcessToken(
    ProcessHandle: THandle; //要修改访问权限的进程句柄
    DesiredAccess: DWORD; //指定你要进行的操作类型
    var TokenHandle: THandle//返回的访问令牌指针
  ): BOOL;

AdjustTokenPrivileges() :调整进程的权限.
  function AdjustTokenPrivileges(
    TokenHandle: THandle;  // 访问令牌的句柄
    DisableAllPrivileges: BOOL; // 决定是进行权限修改还是除能(Disable)所有权限
    const NewState: TTokenPrivileges;  
    { 指明要修改的权限,是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,
      数据组的每个项指明了权限的类型和要进行的操作; }
    BufferLength: DWORD;  
    //结构PreviousState的长度,如果PreviousState为空,该参数应为 0
    var PreviousState: TTokenPrivileges; 
    // 指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息
    var ReturnLength: DWORD //实际PreviousState结构返回的大小
  ) : BOOL;

远程注入DLL其实是通过 CreateRemoteThread 建立一个远程线程调用 LoadLibrary 函数来加载我们指定的DLL,可是如何能让远程线程知道我要加载DLL呢,要知道在Win32系统下,每个进程都拥有自己的4G虚拟地址空间,各个进程之间都是相互独立的。所我们需要在远程进程的内存空间里申请一块内存空间,写入我们的需要注入的 DLL 的路径. 需要用到的 API 函数有:

OpenProcess():打开目标进程,得到目标进程的操作权限,详细参看MSDN
  function OpenProcess(
    dwDesiredAccess: DWORD;  // 希望获得的访问权限
    bInheritHandle: BOOL;  // 指明是否希望所获得的句柄可以继承
    dwProcessId: DWORD // 要访问的进程ID
  ): THandle;

VirtualAllocEx():用于在目标进程内存空间中申请内存空间以写入DLL的文件名
  function VirtualAllocEx(
    hProcess: THandle;  // 申请内存所在的进程句柄
    lpAddress: Pointer;  // 保留页面的内存地址;一般用nil自动分配
    dwSize,  // 欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍
    flAllocationType: DWORD; 
    flProtect: DWORD
  ): Pointer;

WriteProcessMemory():往申请到的空间中写入DLL的文件名
  function WriteProcessMemory(
    hProcess: THandle;  //要写入内存数据的目标进程句柄
    const lpBaseAddress: Pointer; //要写入的目标进程的内存指针, 需以 VirtualAllocEx() 来申请
    lpBuffer: Pointer; //要写入的数据
    nSize: DWORD; //写入数据的大小
    var lpNumberOfBytesWritten: DWORD //实际写入的大小
  ): BOOL;

然后就可以调用 CreateRemoteThread 建立远程线程调用 LoadLibrary 函数来加载我们指定的DLL.

CreateRemoteThread() //在一个远程进程中建立线程
  function CreateRemoteThread(
    hProcess: THandle;  //远程进程的句柄
    lpThreadAttributes: Pointer; //线程安全描述字,指向SECURITY_ATTRIBUTES结构的指针
    dwStackSize: DWORD;  //线程栈大小,以字节表示
    lpStartAddress: TFNThreadStartRoutine;  
    // 一个TFNThreadStartRoutine类型的指针,指向在远程进程中执行的函数地址
    lpParameter: Pointer; //传入参数的指针
    dwCreationFlags: DWORD;  //创建线程的其它标志
    var lpThreadId: DWORD //线程身份标志,如果为0, 则不返回
  ): THandle;

整个远程注入DLL的具体实现代码如下:

function InjectDll(const DllFullPath: stringconst dwRemoteProcessId: Cardinal): Boolean;
var
  hRemoteProcess, hRemoteThread: THandle;
  pszLibFileRemote: Pointer;
  pszLibAFilename: PwideChar;
  pfnStartAddr: TFNThreadStartRoutine;
  memSize, WriteSize, lpThreadId: Cardinal;
begin
  Result := false;
  // 调整权限,使程序可以访问其他进程的内存空间
  if EnableDebugPriv then
  begin
    //打开远程线程 PROCESS_ALL_ACCESS 参数表示打开所有的权限
    hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId);

try

// 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2
      GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1);
      // 之所以要转换成 WideChar, 是因为当DLL位于有中文字符的路径下时不会出错
      StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1);
      // 计算 pszLibAFilename 的长度,注意,是以字节为单元的长度
      memSize := (1 + lstrlenW(pszLibAFilename)) * SizeOf(WCHAR);

//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间
      pszLibFileRemote := VirtualAllocEx(hRemoteProcess, nil,
        memSize, MEM_COMMIT, PAGE_READWRITE);

if Assigned(pszLibFileRemote) then
      begin
        //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间
        if WriteProcessMemory(hRemoteProcess, pszLibFileRemote,
          pszLibAFilename, memSize, WriteSize) and

(WriteSize = memSize) then
        begin
          lpThreadId := 0;
          // 计算LoadLibraryW的入口地址
          pfnStartAddr := GetProcAddress(LoadLibrary(‘Kernel32.dll‘),
            ‘LoadLibraryW‘);
          // 启动远程线程LoadLbraryW,通过远程线程调用创建新的线程
          hRemoteThread := CreateRemoteThread(hRemoteProcess, nil,
            0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId);

// 如果执行成功返回 True;
          if (hRemoteThread <> 0) then
            Result := true;

// 释放句柄
          CloseHandle(hRemoteThread);
        end;
      end;
    finally
      // 释放句柄
      CloseHandle(hRemoteProcess);
    end;
  end;
end;

接下来要说的是如何卸载注入目标进程中的DLL,其实原理和注入DLL是完全相同的,只是远程调用调用的函数不同而已,这里要调用的是FreeLibrary,代码如下:

function UnInjectDll(const DllFullPath: stringconst dwRemoteProcessId: Cardinal): Boolean;
  // 进程注入和取消注入其实都差不多,只是运行的函数不同而已
var
  hRemoteProcess, hRemoteThread: THandle;
  pszLibFileRemote: PChar;
  pszLibAFilename: PwideChar;
  pfnStartAddr: TFNThreadStartRoutine;
  memSize, WriteSize, lpThreadId, dwHandle: Cardinal;
begin
  Result := false;

// 调整权限,使程序可以访问其他进程的内存空间
  if EnableDebugPriv then
  begin
    //打开远程线程 PROCESS_ALL_ACCESS 参数表示打开所有的权限
    hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, false, dwRemoteProcessId);

try

// 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2
      GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1);
      // 之所以要转换成 WideChar, 是因为当DLL位于有中文字符的路径下时不会出错
      StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1);
      // 计算 pszLibAFilename 的长度,注意,是以字节为单元的长度
      memSize := (1 + lstrlenW(pszLibAFilename)) * SizeOf(WCHAR);

//使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间
      pszLibFileRemote := VirtualAllocEx(hRemoteProcess, nil,
        memSize, MEM_COMMIT, PAGE_READWRITE);

if Assigned(pszLibFileRemote) then
      begin
        //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间
        if WriteProcessMemory(hRemoteProcess, pszLibFileRemote,
          pszLibAFilename, memSize, WriteSize) and

(WriteSize = memSize) then
        begin
          // 计算GetModuleHandleW的入口地址
          pfnStartAddr := GetProcAddress(LoadLibrary(‘Kernel32.dll‘),
            ‘GetModuleHandleW‘);
          //使目标进程调用GetModuleHandleW,获得DLL在目标进程中的句柄
          hRemoteThread := CreateRemoteThread(hRemoteProcess, nil,
            0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId);
          // 等待GetModuleHandle运行完毕
          WaitForSingleObject(hRemoteThread, INFINITE);
          // 获得GetModuleHandle的返回值,存在dwHandle变量中
          GetExitCodeThread(hRemoteThread, dwHandle);

// 计算FreeLibrary的入口地址
          pfnStartAddr := GetProcAddress(LoadLibrary(‘Kernel32.dll‘),
            ‘FreeLibrary‘);
          // 使目标进程调用FreeLibrary,卸载DLL
          hRemoteThread := CreateRemoteThread(hRemoteProcess, nil,
            0, pfnStartAddr, Pointer(dwHandle), 0, lpThreadId);
          // 等待FreeLibrary卸载完毕
          WaitForSingleObject(hRemoteThread, INFINITE);

// 如果执行成功返回 True;
          if hRemoteProcess <> 0 then
            Result := true;

// 释放目标进程中申请的空间
          VirtualFreeEx(hRemoteProcess, pszLibFileRemote,
            Length(DllFullPath) + 1, MEM_DECOMMIT);
          // 释放句柄
          CloseHandle(hRemoteThread);
        end;
      end;
    finally
      // 释放句柄
      CloseHandle(hRemoteProcess);
    end;
  end;
end;

注意:例程里注入的DLL为例程目录下的DLL.dll,由DLL.dpr编译而来

时间: 2024-10-12 08:56:12

实战DELPHI:远程线程插入(DLL注入)的相关文章

远程线程注入

一丶远程线程注入的讲解 远程线程注入的原理,我会写一个远程线程开发的例子 我们总共需要几步 /*1.查找窗口,获取窗口句柄*/ /*2.根据窗口句柄,获得进程的PID*/ /*3.根据进程的PID,获得进程的句柄*/ /*4.根据进程的句柄,给进程申请额外内存空间*/ /*5.调用WriteProcessMemory,给进程写入DLL的路径*/ /*6.创建远程线程,执行我们的代码*/ /*7.调用退出代码,释放远程线程的dll*/ 每一步单独讲解 我们新建一个MFC 对话框程序,添加一个按钮,

[转]Dll注入经典方法完整版

Pnig0s1992:算是复习了,最经典的教科书式的Dll注入. 总结一下基本的注入过程,分注入和卸载 注入Dll: 1,OpenProcess获得要注入进程的句柄 2,VirtualAllocEx在远程进程中开辟出一段内存,长度为strlen(dllname)+1; 3,WriteProcessMemory将Dll的名字写入第二步开辟出的内存中. 4,CreateRemoteThread将LoadLibraryA作为线程函数,参数为Dll的名称,创建新线程 5,CloseHandle关闭线程句

Dll注入:X86/X64 远程线程CreateRemoteThread 注入

远线程注入原理是利用Windows 系统中CreateRemoteThread()这个API,其中第4个参数是准备运行的线程,我们可以将LoadLibrary()填入其中,这样就可以执行远程进程中的LoadLibrary()函数,进而将我们自己准备的DLL加载到远程进程空间中执行. 函数原型: HANDLE WINAPI CreateRemoteThread( _In_ HANDLE hProcess, //远程线程的句柄 _In_opt_ LPSECURITY_ATTRIBUTES lpThr

[转载]Dll注入技术之远程线程注入

转自:黑客反病毒 DLL注入技术之远线程注入 DLL注入技术指的是将一个DLL文件强行加载到EXE文件中,并成为EXE文件中的一部分,这样做的目的在于方便我们通过这个DLL读写EXE文件内存数据,(例如 HOOK EXE文件中的API),或以被注入EXE的身份去执行一些操作等等.     远线程注入原理是利用Windows 系统中CreateRemoteThread()这个API,其中第4个参数是准备运行的线程,我们可以将LoadLibrary()填入其中,这样就可以执行远程进程中的LoadLi

奇技淫巧之调试被远程线程注入的DLL

远程线程注入, 这东西大家都懂的, 一般都被大家用来干些小小的坏事情,比如API Hook~~将DLL注入到其它进程并不是难事,问题是这个被注入的DLL不太好调试,调试DLL本来就是个比较头疼的问题,更何况是这种运行在其它进程空间的DLL, 被注入DLL的程序,不崩溃还好,崩溃了,要定位崩溃点,真是够麻烦的. 这几天,无意中发现了一个可以调试这种DLL的方法. 首先,需要准备两样东西: 1.微软的Detours库, 下载地址戳这里: 下载链接 2.打开Detours安装目录下的samples\s

【windows核心编程】使用远程线程注入DLL

前言 该技术是指通过在[目标进程]中创建一个[远程线程]来达到注入的目的. 创建的[远程线程]函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写.  示意图如下:  相关API 1.创建远程线程 //该函数除了第一个参数为目标进程句柄外 //其他参数均和CreateThread一样 HANDLE hThread = CreateRemoteThread( __in HANDLE hProcess, //目标进程句柄 __in_opt LPSECURITY_A

远程线程注入dll

// CommonInject.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <WinUser.h> #include <WinDef.h> #include <iostream> #include <Tlhelp32.h> using namespa

CreateRemoteThread远程线程注入Dll与Hook

CreateRemoteThread虽然很容易被检测到,但是在有些场合还是挺有用的.每次想用的时候总想着去找以前的代码,现在在这里记录一下. CreateRemoteThread远程注入 DWORD dwOffect,dwArgu; BOOL CreateRemoteDll(const char *DllFullPath, const DWORD dwRemoteProcessId ,DWORD dwOffect,DWORD dwArgu) { HANDLE hToken; if ( OpenP

安全之路 —— 无DLL文件实现远程线程注入

简介 在之前的章节中,笔者曾介绍过有关于远程线程注入的知识,将后门.dll文件注入explorer.exe中实现绕过防火墙反弹后门.但一个.exe文件总要在注入时捎上一个.dll文件着实是怪麻烦的,那么有没有什么方法能够不适用.dll文件实现注入呢? 答案是有的,我们可以直接将功能写在线程函数中,然后直接将整个函数注入,这个方法相较之于DLL注入会稍微复杂一些,适用于对一些体积比较小的程序进行注入.但是要注意动态链接库的地址重定位问题,因为正常的文件一般会默认载入kernel32.dll文件,而