闲着没事整理了一下DLL的N种注入方法.docx

上传人:b****5 文档编号:6737979 上传时间:2023-01-09 格式:DOCX 页数:57 大小:45.40KB
下载 相关 举报
闲着没事整理了一下DLL的N种注入方法.docx_第1页
第1页 / 共57页
闲着没事整理了一下DLL的N种注入方法.docx_第2页
第2页 / 共57页
闲着没事整理了一下DLL的N种注入方法.docx_第3页
第3页 / 共57页
闲着没事整理了一下DLL的N种注入方法.docx_第4页
第4页 / 共57页
闲着没事整理了一下DLL的N种注入方法.docx_第5页
第5页 / 共57页
点击查看更多>>
下载资源
资源描述

闲着没事整理了一下DLL的N种注入方法.docx

《闲着没事整理了一下DLL的N种注入方法.docx》由会员分享,可在线阅读,更多相关《闲着没事整理了一下DLL的N种注入方法.docx(57页珍藏版)》请在冰豆网上搜索。

闲着没事整理了一下DLL的N种注入方法.docx

闲着没事整理了一下DLL的N种注入方法

闲着没事整理了一下DLL的N种注入方法,对学习外挂的朋友,应该有用!

第一种方法:

利用CreateRemoteThread远程建立线程的方式注入DLL.

首先,我们要提升自己的权限,因为远程注入必不可免的要访问到目

标进程的内存空间,如果没有足够的系统权限,将无法作任何事.下

面是这个函数是用来提升我们想要的权限用的.

functionEnableDebugPriv:

Boolean;

var

  hToken:

THANDLE;

  tp:

TTokenPrivileges;

  rl:

Cardinal;

begin

  result:

=false;

  //打开进程令牌环

  OpenProcessToken(GetCurrentProcess(),

TOKEN_ADJUST_PRIVILEGESorTOKEN_QUERY,hToken);

  //获得进程本地唯一ID

  ifLookupPrivilegeValue(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():

获得进程访问令牌的句柄.

  functionOpenProcessToken(

  ProcessHandle:

THandle;//要修改访问权限的进程句柄

  DesiredAccess:

DWORD;//指定你要进行的操作类型

  varTokenHandle:

THandle

  ):

BOOL;//返回的访问令牌指针

AdjustTokenPrivileges():

调整进程的权限.

  functionAdjustTokenPrivileges(

  TokenHandle:

THandle;  //访问令牌的句柄

  DisableAllPrivileges:

BOOL;//决定是进行权限修改还是除

能(Disable)所有权限

  constNewState:

TTokenPrivileges;  //指明要修改的权限,

是一个指向TOKEN_PRIVILEGES结构的指针,该结构包含一个数组,数

据组的每个项指明了权限的类型和要进行的操作;

  BufferLength:

DWORD;  //结构PreviousState的长度,如果

PreviousState为空,该参数应为0

  varPreviousState:

TTokenPrivileges;//指向

TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息

  varReturnLength:

DWORD//实际PreviousState结构返回的大

  ):

BOOL;

远程注入DLL其实是通过CreateRemoteThread建立一个远程线程调

用LoadLibrary函数来加载我们指定的DLL,可是如何能让远程线程

知道我要加载DLL呢,要知道在Win32系统下,每个进程都拥有自己的

4G虚拟地址空间,各个进程之间都是相互独立的。

所我们需要在远程

进程的内存空间里申请一块内存空间,写入我们的需要注入的DLL

的路径.需要用到的API函数有:

OpenProcess():

打开目标进程,得到目标进程的操作权限,详细参

看MSDN

  functionOpenProcess(

  dwDesiredAccess:

DWORD;  //希望获得的访问权限

  bInheritHandle:

BOOL;  //指明是否希望所获得的句柄可以继

  dwProcessId:

DWORD//要访问的进程ID

  ):

THandle;

VirtualAllocEx():

用于在目标进程内存空间中申请内存空间以写入

DLL的文件名

  functionVirtualAllocEx(

  hProcess:

THandle;  //申请内存所在的进程句柄

  lpAddress:

Pointer;  //保留页面的内存地址;一般用nil自

动分配

  dwSize,  //欲分配的内存大小,字节单位;注意实际分配的

内存大小是页内存大小的整数倍

  flAllocationType:

DWORD;

  flProtect:

DWORD

  ):

Pointer;

WriteProcessMemory():

往申请到的空间中写入DLL的文件名

  functionWriteProcessMemory(

  hProcess:

THandle;  //要写入内存数据的目标进程句柄

  constlpBaseAddress:

Pointer;//要写入的目标进程的内存指

针,需以VirtualAllocEx()来申请

  lpBuffer:

Pointer;//要写入的数据

  nSize:

DWORD;//写入数据的大小

  varlpNumberOfBytesWritten:

DWORD//实际写入的大小

  ):

BOOL;

然后就可以调用CreateRemoteThread建立远程线程调用

LoadLibrary函数来加载我们指定的DLL.

CreateRemoteThread() //在一个远程进程中建立线程

  functionCreateRemoteThread(

  hProcess:

THandle;  //远程进程的句柄

  lpThreadAttributes:

Pointer;//线程安全描述字,指向

SECURITY_ATTRIBUTES结构的指针

  dwStackSize:

DWORD;  //线程栈大小,以字节表示

  lpStartAddress:

TFNThreadStartRoutine;  //一个

TFNThreadStartRoutine类型的指针,指向在远程进程中执行的函数

地址

  lpParameter:

Pointer;//传入参数的指针

  dwCreationFlags:

DWORD;  //创建线程的其它标志

  varlpThreadId:

DWORD//线程身份标志,如果为0,则不返回

  ):

THandle;

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

functionInjectDll(constDllFullPath:

string;const

dwRemoteProcessId:

Cardinal):

boolean;

var

  hRemoteProcess,hRemoteThread:

THANDLE;

  pszLibFileRemote:

Pointer;

  pszLibAFilename:

PwideChar;

  pfnStartAddr:

TFNThreadStartRoutine;

  memSize,WriteSize,lpThreadId:

Cardinal;

begin

  result:

=FALSE;

  //调整权限,使程序可以访问其他进程的内存空间

  ifEnableDebugPrivthen

  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);

    ifAssigned(pszLibFileRemote)then

    begin

      //使用WriteProcessMemory函数将DLL的路径名写入到远程

进程的内存空间

      ifWriteProcessMemory(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.代码如下:

functionUnInjectDll(constDllFullPath:

string;  const

dwRemoteProcessId:

Cardinal):

Boolean;

//进程注入和取消注入其实都差不多,只是运行的函数不同而已

var

  hRemoteProcess,hRemoteThread:

THANDLE;

  pszLibFileRemote:

pchar;

  pszLibAFilename:

PwideChar;

  pfnStartAddr:

TFNThreadStartRoutine;

  memSize,WriteSize,lpThreadId,dwHandle:

Cardinal;

begin

  result:

=FALSE;

  //调整权限,使程序可以访问其他进程的内存空间

  ifEnableDebugPrivthen

  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);

    ifAssigned(pszLibFileRemote)then

    begin

      //使用WriteProcessMemory函数将DLL的路径名写入到远程

进程的内存空间

      ifWriteProcessMemory(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;

      ifhRemoteProcess<>0then

        result:

=TRUE;

      //释放目标进程中申请的空间

      VirtualFreeEx(hRemoteProcess,pszLibFileRemote,

Length(DllFullPath)+1,MEM_DECOMMIT);

      //释放句柄

      CloseHandle(hRemoteThread);

      end;

    end;

  finally

    //释放句柄

    CloseHandle(hRemoteProcess);

  end;

  end;

end;

第二种方法:

采用CreateProcess的方法,实现起来比较复杂,但没有上面几种方法的局限性。

且可以用其他工

具(VC等)调试注入的DLL。

下面进行介绍。

原理如下:

1.  用CreateProcess(CREATE_SUSPENDED)启动目标进程。

2.  找到目标进程的入口,用ImageHlp中的函数可以实现。

3.  将目标进程入口的代码保存起来。

4.  在目标进程的入口写入LoadLibrary(MyDll)实现Dll的注入。

5.  用ResumeThread运行目标进程。

6.  目标进程就运行了LoadLibrary(MyDll),实现DLL的注入。

7.  目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口。

8.  目标进程Jmp至原来的入口,继续运行程序。

从原理上可以看出,DLL的注入在目标进程的开始就运行了,而且不是用Debug的方案,这样,就

没有上面方案的局限性了。

该方案的关键在6,7,8三步,实现方法需要监视进程和DLL合作。

面,结合代码进行分析。

在监视进程中,创建FileMapping,用来保存目标进程的入口代码,同时保证DLL中可以访问。

第7步实现将原目标代码写回目标进程的入口。

//监视程序和DLL共用的结构体

#pragmapack(push,1)  //保证下面的结构体采用BYTE对齐(必须)

typedefstruct

{

    BYTE    int_PUSHAD;      //pushad      0x60    

    BYTE    int_PUSH;        //push&szDLL    0x68

    DWORDpush_Value;        //        &szDLL="ApiSpy.dll"的path

    BYTE    int_MOVEAX;          //  moveeax&LoadLibrary  0xB8

    DWORDeax_Value;        //    &LoadLibrary

    WORD  call_eax;      //    calleax  0xD0FF(FFD0)(LoadLibrary

("ApiSpy.dll");

    BYTE    jmp_MOVEAX;        //    moveeax&ReplaceOldCode  0xB8    

    DWORDjmp_Value;        //    JMP的参数

    WORD  jmp_eax;      //    jmpeax  0xE0FF(FFE0)jmpReplaceOldCode;

    charszDLL[MAX_PATH];//  "ApiSpy.dll"的FullPath

}INJECT_LOADLIBRARY_CODE,*LPINJECT_CODE;

#pragmapack(pop,1)

上面结构体的代码为汇编代码,对应的汇编为:

pushad

pushszDll

moveax,&LoadLibraryA

calleax  //实现调用LoadLibrary(szDll)的代码

moveax,oldentry

jmpeax//实现在LoadLibrary运行完后,跳至目标进程的入口继续运行

//FileMaping的结构体

typedefstruct

{

    LPBYTE  lpEntryPoint;  //目标进程的入口地址

    BYTE    oldcode[sizeof(INJECT_CODE)];      //目标进程的代码保存

}SPY_MEM_SHARE,*LPSPY_MEM_SHARE;

准备工作:

第一步:

用CreateProcess(CREATE_SUSPENDED)启动目标进程。

CreateProcessA(0,szRunFile,0,0,FALSE,CREATE_SUSPENDED

                  0,NULL,&stInfo,

                  &m_proInfo);

//用CreateProcess启动一个暂停的目标进程

//找到目标进程的入口点,函数如下

第二步:

找到目标进程的入口,用I

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1