DLL的11种注入方法资料

  • 格式:doc
  • 大小:151.50 KB
  • 文档页数:55

闲着没事整理了一下DLL的N种注入方法,对学习外挂的朋友,应该有用!第一种方法:利用CreateRemoteThread 远程建立线程的方式注入DLL.首先,我们要提升自己的权限,因为远程注入必不可免的要访问到目标进程的内存空间,如果没有足够的系统权限,将无法作任何事.下面是这个函数是用来提升我们想要的权限用的.function EnableDebugPriv : Boolean;varhToken : THANDLE;tp : TTokenPrivileges;rl : Cardinal;beginresult := false;//打开进程令牌环OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);//获得进程本地唯一IDif LookupPrivilegeValue(nil, 'SeDebugPrivilege',tp.Privileges[0].Luid) thenbegintp.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为空,该参数应为0var PreviousState: TTokenPrivileges; // 指向TOKEN_PRIVILEGES结构的指针,存放修改前的访问权限的信息var ReturnLength: DWORD //实际PreviousState结构返回的大小) : BOOL;远程注入DLL其实是通过CreateRemoteThread 建立一个远程线程调用LoadLibrary 函数来加载我们指定的DLL,可是如何能让远程线程知道我要加载DLL呢,要知道在Win32系统下,每个进程都拥有自己的4G虚拟地址空间,各个进程之间都是相互独立的。

所我们需要在远程进程的内存空间里申请一块内存空间,写入我们的需要注入的DLL的路径.需要用到的API 函数有:OpenProcess():打开目标进程,得到目标进程的操作权限,详细参看MSDNfunction 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 : string; const dwRemoteProcessId : Cardinal): boolean;varhRemoteProcess, hRemoteThread: THANDLE;pszLibFileRemote : Pointer;pszLibAFilename: PwideChar;pfnStartAddr : TFNThreadStartRoutine;memSize, WriteSize, lpThreadId : Cardinal;beginresult := FALSE;// 调整权限,使程序可以访问其他进程的内存空间if EnableDebugPriv thenbegin//打开远程线程PROCESS_ALL_ACCESS 参数表示打开所有的权限hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId );try// 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2GetMem(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) thenbegin//使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间if WriteProcessMemory(hRemoteProcess,pszLibFileRemote, pszLibAFilename, memSize, WriteSize) and (WriteSize = memSize) thenbeginlpThreadId := 0;// 计算LoadLibraryW的入口地址pfnStartAddr := GetProcAddress(LoadLibrary('Kernel32.dll'), 'LoadLibraryW');// 启动远程线程LoadLbraryW,通过远程线程调用创建新的线程hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0, pfnStartAddr, pszLibFileRemote, 0, lpThreadId);// 如果执行成功返回True;if (hRemoteThread <> 0) thenresult := TRUE;// 释放句柄CloseHandle(hRemoteThread);end;end;finally// 释放句柄CloseHandle(hRemoteProcess);end;end;end;接下来要说的是如何卸载注入目标进程中的DLL,其实原理和注入DLL 是完全相同的,只是远程调用调用的函数不同而已,这里要调用的是FreeLibrary.代码如下:function UnInjectDll(const DllFullPath : string; const dwRemoteProcessId : Cardinal) : Boolean;// 进程注入和取消注入其实都差不多,只是运行的函数不同而已varhRemoteProcess, hRemoteThread : THANDLE;pszLibFileRemote : pchar;pszLibAFilename: PwideChar;pfnStartAddr : TFNThreadStartRoutine;memSize, WriteSize, lpThreadId, dwHandle : Cardinal;beginresult := FALSE;// 调整权限,使程序可以访问其他进程的内存空间if EnableDebugPriv thenbegin//打开远程线程PROCESS_ALL_ACCESS 参数表示打开所有的权限hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId );try// 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2GetMem(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) thenbegin//使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间if WriteProcessMemory(hRemoteProcess, pszLibFileRemote, pszLibAFilename, memSize, WriteSize) and (WriteSize = memSize) thenbegin// 计算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,卸载DLLhRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0,pfnStartAddr, Pointer(dwHandle), 0, lpThreadId);// 等待FreeLibrary卸载完毕WaitForSingleObject( hRemoteThread, INFINITE );// 如果执行成功返回True;if hRemoteProcess<>0 thenresult := TRUE;// 释放目标进程中申请的空间VirtualFreeEx(hRemoteProcess, pszLibFileRemote,Length(DllFullPath)+1, MEM_DECOMMIT);// 释放句柄CloseHandle(hRemoteThread);end;end;finally// 释放句柄CloseHandle(hRemoteProcess);end;end;end;第二种方法:采用CreateProcess的方法,实现起来比较复杂,但没有上面几种方法的局限性。