DLL的11种注入方法_第1页
DLL的11种注入方法_第2页
DLL的11种注入方法_第3页
DLL的11种注入方法_第4页
DLL的11种注入方法_第5页
已阅读5页,还剩50页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

闲着没事整理了一下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.Privileges0.Luid) thenbegin tp.PrivilegeCount := 1; tp.Privileges0.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():打开目标进程,得到目标进程的操作权限,详细参看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 函数来加载我们指定的DLLCreateRemoteThread()/在一个远程进程中建立线程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,故要乘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 : 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,故要乘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 hRemoteProcess0 then 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共用的结构体#pragma pack (push ,1) 保证下面的结构体采用BYTE对齐(必须)typedef struct BYTE int_PUSHAD; / pushad 0x60 BYTE int_PUSH; / push &szDLL 0x68 DWORD push_Value; / &szDLL = ApiSpy.dll的path BYTE int_MOVEAX; /move eax &LoadLibrary0xB8 DWORD eax_Value; / &LoadLibrary WORD call_eax; / call eax 0xD0FF(FF D0) (LoadLibrary(ApiSpy.dll); BYTE jmp_MOVEAX; / move eax &ReplaceOldCode0xB8 DWORD jmp_Value; / JMP的参数 WORD jmp_eax; / jmp eax 0xE0FF(FF E0) jmp ReplaceOldCode; char szDLLMAX_PATH; /ApiSpy.dll的FullPathINJECT_LOADLIBRARY_CODE, *LPINJECT_CODE;#pragma pack (pop , 1)上面结构体的代码为汇编代码,对应的汇编为:pushadpush szDllmov eax, &LoadLibraryAcall eax/ 实现调用LoadLibrary(szDll)的代码mov eax, oldentryjmp eax / 实现在LoadLibrary运行完后, 跳至目标进程的入口继续运行/ FileMaping的结构体typedef struct LPBYTElpEntryPoint; / 目标进程的入口地址 BYTE oldcodesizeof(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启动一个暂停的目标进程/ 找到目标进程的入口点,函数如下第二步:找到目标进程的入口,用ImageHlp中的函数可以实现。pEntryPoint = GetExeEntryPoint(szRunFile);LPBYTEGetExeEntryPoint(char *filename) PIMAGE_NT_HEADERS pNTHeader; DWORD pEntryPoint; PLOADED_IMAGE pImage; pImage = ImageLoad(filename, NULL); if(pImage = NULL) return NULL; pNTHeader = pImage-FileHeader; pEntryPoint = pNTHeader-OptionalHeader.AddressOfEntryPoint + pNTHeader-OptionalHeader.ImageBase; ImageUnload(pImage); return (LPBYTE)pEntryPoint;/ 创建FileMappinghMap = CreateFileMapping(HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, sizeof(SPY_MEM_SHARE), “MyDllMapView”);/ 保存目标进程的代码第三步:将目标进程入口的代码保存起来。LPSPY_MEM_SHARE lpMap = pMapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);ReadProcessMemory(m_proInfo.hProcess, pEntryPoint, &lpMap-oldcode, sizeof(INJECT_CODE), &cBytesMoved); lpMap-lpEntryPoint = pEntryPoint;/ 第四步:在目标进程的入口写入LoadLibrary(MyDll)实现Dll的注入。/ 准备注入DLL的代码 INJECT_CODE newCode;/ 写入MyDll用全路径 lstrcpy(newCode.szDLL, szMyDll);/ 准备硬代码(汇编代码) newC_PUSHAD = 0x60; newC_PUSH = 0x68; newC_MOVEAX = 0xB8; newCode.call_eax = 0xD0FF; newCode.jmp_MOVEAX = 0xB8; newCode.jmp_eax = 0xE0FF; newCode.eax_Value = (DWORD)LoadLibrary; newCode.push_Value=(pEntryPoint + offsetof(INJECT_CODE,szDLL);/ 将硬代码写入目标进程的入口/ 修改内存属性DWORD dwNewFlg, dwOldFlg;dwNewFlg = PAGE_READWRITE;VirtualProtectEx(m_proInfo.hProcess, (LPVOID)pEntryPoint, sizeof(DWORD), dwNewFlg, &dwOldFlg);WriteProcessMemory(m_proInfo.hProcess, pEntryPoint, &newCode, sizeof(newCode), NULL);/&dwWrited); VirtualProtectEx(proInfo.hProcess, (LPVOID)pEntryPoint, sizeof(DWORD), dwOldFlg, &dwNewFlg);/ 释放FileMaping注意,不是Closehandle(hMap)UnmapViewOfFile(lpMap);/ 继续目标进程的运行第五步:用ResumeThread运行目标进程。ResumeThread(m_proInfo.hThread);在监视进程中就结束了自己的任务,剩下的第6,7,8步就需要在Dll的DllMain中进行配合。DLL中用来保存数据的结构体typedef struct DWORD lpEntryPoint; DWORD OldAddr; DWORD OldCode4;JMP_CODE,* LPJMP_CODE;static JMP_CODE_lpCode;/ 在DllMain的DLL_PROCESS_ATTACH中调用InitApiSpy函数/ 在该函数中实现第6,7,8步第六步:目标进程就运行了LoadLibrary(MyDll),实现DLL的注入。int WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved) switch(dwReason) case DLL_PROCESS_ATTACH: return InitApiSpy();/ InitApiSpy函数的实现BOOL WINAPI InitApiSpy() HANDLE hMap; LPSPY_MEM_SHARE lpMem; DWORD dwSize; BOOL rc; BYTE* lpByte; / 取得FileMapping的句柄 hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, “MyDllMapView”); if(hMap) lpMem = (LPSPY_MEM_SHARE)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if(lpMem) 第七步:目标进程运行完LoadLibrary(MyDll)后,将原来的代码写回目标进程的入口。 / 恢复目标进程的入口代码/ 得到mov eax, value代码的地址 _lpCode.OldAddr = (DWORD)(BYTE*)lpMem-lpEntryPoint + offsetof(INJECT_CODE, jmp_MOVEAX); _lpCode.lpEntryPoint = (DWORD)lpMem-lpEntryPoint; / 保存LoadLibrary()后面的代码 memcpy(&_lpCode.OldCode, (BYTE*)lpMem-oldcode + offsetof(INJECT_CODE, jmp_MOVEAX), 2*sizeof(DWORD); / 恢复目标进程的入口代码 rc = WriteProcessMemory(GetCurrentProcess(), lpMem-lpEntryPoint, lpMem-oldcode, sizeof(INJECT_CODE), &dwSize); lpByte = (BYTE*)lpMem-lpEntryPoint + offsetof(INJECT_CODE, jmp_MOVEAX); UnmapViewOfFile(lpMem); CloseHandle(hMap); / 实现自己Dll的其他功能,如导入表的替换/ / 将LoadLibrary后面的代码写为转入处理程序中/ 指令为:mov eax, objAddress/ jmp eax BYTE* lpMovEax; DWORD* lpMovEaxValu; WORD*lpJmp; DWORD fNew, fOld; fNew = PAGE_READWRITE; lpMovEax = lpByte; VirtualProtect(lpMovEax, 2*sizeof(DWORD), fNew, &fOld); *lpMovEax = 0xB8; lpMovEaxValu = (DWORD*)(lpMovEax + 1); *lpMovEaxValu = (DWORD)&DoJmpEntryPoint; lpJmp = (WORD*)(lpMovEax + 5); *lpJmp = 0xE0FF;/ (FF E0) VirtualProtect(lpMovEax, 2*sizeof(DWORD), fOld, &fNew); return TRUE;/ 转入处理程序DWORD* lpMovEax;DWORD fNew, fOld;void _declspec(naked) DoJmpEntryPoint ()/ 恢复LoadLibrary后面的代码 _gfNew = PAGE_READWRITE; _glpMovEax = (DWORD*)_lpCode.OldAddr; VirtualProtect(_glpMovEax, 2*sizeof(DWORD), _gfNew, &_gfOld); *_glpMovEax = _lpCode.OldCode0; *(_glpMovEax + 1) = _lpCode.OldCode1; VirtualProtect(_glpMovEax, 2*sizeof(DWORD), _gfOld, &_gfNew);第八步:目标进程Jmp至原来的入口,继续运行程序。/ 跳至目标代码的入口 _asm popad _asm jmp _lpCode.lpEntryPoint这样就实现了原来的目标,将DLL的注入放在目标进程的入口运行,实现了目标进程运行之前运行我们的注入Dll的功能。第三种方法:利用注册表注入 在Windows NT/2000/XP/2003中,有一个注册表键值HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsHKEY_LOCAL_MACHINESoftwareMicrosoftWindows NTCurrentVersionWindowsAppInit_DLLs。当某个进程加载User32.dll时,这里面列出的所有的DLL都将User32.dll利用LoadLibrary函数加载到该进程空间中。我们可以把自己的代码放在一个DLL中,并加入该键值,这样就可以注入到所有使用User32.dll的进程中了。 当DLL以LoadLibrary的方式加载时,DllMain会被以DLL_PROCESS_ATTACH为原因调用,实际上我们也只需要关心DLL_PROCESS_ATTACHBOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) if (ul_reason_for_call = DLL_PROCESS_ATTACH) HANDLE f = CreateFile(LD:InjectSuccess.txt, FILE_ADD_FILE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); CloseHandle(f); return TRUE;第四种方法: 利用Windows Hooks注入 Windows系统给我们提供了一些挂钩函数,使得被挂钩的进程可以在自己处理接收到的消息之前,先执行我们的消息处理函数,而这个消息处理函数一般会放在DLL中,来让目标进程加载,这实际上已经达到了注入代码的效果。 一般情况下,我们把挂钩函数和消息处理函数都放在dll中:HHOOK g_hHook = NULL;HINSTANCE hInst;BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) hInst = (HINSTANCE)hModule; return TRUE;LRESULT myKeyBrdFuncAd (int code, WPARAM wParam, LPARAM lParam) / To be nice, your rootkit should call the next-lower / hook, but you never know what this hook may be. /:MessageBoxA(NULL, Hello Injection, Injection, MB_OK); return CallNextHookEx(g_hHook, code, wParam, lParam);#ifdef _cplusplus / If used by C+ code, extern C / we need to export the C interface#endif_declspec(dllexport) bool SetHook(DWORD dwThreadId)g_hHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)myKeyBrdFuncAd, hInst, dwThreadId);if (g_hHook = NULL) return false;return true;#ifdef _cplusplus#endif 注入进程要加载这个DLL,然后执行里面的SetHook函数,传入的参数为被注入线程的ID typedef bool (*MYPROC) (DWORD dwThreadId); . HANDLE hLib = LoadLibraryA(D:sourcerootkitsinjectingInjectDllDebugInjectDll.dll);if (hLib = NULL) printf(LoadLibrary Error!n);MYPROC myProc = (MYPROC)GetProcA

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论