DLL注入
今天整理了下DLL注入用到的APi,用delphi写了个demo,有兴趣的同学可以转换成C语言的。源码下载:
DLL注入.rar
(386.01 KB)
程序代码:
{总体流程: 利用CreateToolhelp32Snapshot函数创建一个进程快照,然后利用Process32First函数和 Process32Next函数遍历出所有进程ID等信息,保存到ListView控件中。当获取到进程ID后 交给OpenProcess函数使用打开一个进程,从而获取一个进程句柄,当获取进程句柄后则交 给VirtualAllocEx和WriteProcessMemory函数使用,从而进行虚拟内存分配和写入。然后 则利用GetProcAddress函数和GetModuleHandle函数获取定的动态链接库'kernel32.dll'中 的'LoadLibraryA'函数地址。然后把这个地址交给CreateRemoteThread函数使用。最后用 WaitForSingleObject、VirtualFreeEx、CloseHandle清楚现场。} unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, TLHelp32, ComCtrls; type TForm1 = class(TForm) Button1: TButton; ListView1: TListView; Button2: TButton; Button3: TButton; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; hProcess:THandle; Procedure GetProcess(); function LoadLibraryA(lpLibFileName: PAnsiChar): HMODULE; stdcall; external kernel32 name 'LoadLibraryA'; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject);begin GetProcess; end; Procedure GetProcess(); var hSnapshot:THandle; pe32:TProcessEntry32; item:TListItem; count:Integer; begin count:=1; hSnapshot:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if hSnapshot=0 then begin Form1.Caption:='创建进程快照失败!'; Abort(); end else begin Form1.Caption:='创建进程快照成功!'; end; pe32.dwSize:=SizeOf(PROCESSENTRY32); if not Process32First(hSnapshot,pe32) then begin Form1.Caption:='获取第'+IntToStr(count)+'个进程失败!'; end else begin Form1.Caption:='获取第'+IntToStr(count)+'个进程成功!'; end; Form1.ListView1.Clear; repeat count:=count+1; Form1.Caption:='获取第'+IntToStr(count)+'个进程成功!'; item:=Form1.ListView1.Items.Add; item.Caption:=IntToStr(pe32.th32ProcessID); item.SubItems.Add(pe32.szExeFile); item.SubItems.Add(IntToStr(pe32.pcPriClassBase)); item.SubItems.Add(IntToStr(pe32.th32ParentProcessID)); until not Process32Next(hSnapshot,pe32); Form1.Caption:='成功获取'+IntToStr(count)+'个进程!'; end; procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage('程序名称:DLL注入'+#13+ '版本:1.0.0.0'+#13+ '日期:2010-10-5'+#13+ '作者:江湖一键客'+#13+ '业务联系QQ:82530662'); end; procedure TForm1.Button3Click(Sender: TObject); var lpBaseAddress:Pointer; flProtect: DWORD; lNOBW: DWORD; fileName:String; len:Integer; wFlag:Bool; pLoadLibrary:FARPROC; lpThreadId:DWORD; hThread:THandle; begin if OpenDialog1.Execute then begin fileName:=OpenDialog1.FileName; len:=Length(fileName)+1; end else begin Abort(); end; lpBaseAddress:=VirtualAllocEx(hProcess,nil,Len,MEM_COMMIT,PAGE_READWRITE); if lpBaseAddress=nil then begin Form1.Caption:='分配虚拟内存失败!'; Abort(); end; Form1.Caption:='分配虚拟内存成功'; wFlag:=WriteProcessMemory(hProcess,lpBaseAddress,pchar(@fileName[1]),len,lNOBW); if (not wFlag) and (lNOBW<>len) then begin Form1.Caption:='写入内存失败!'; VirtualFreeEx(hProcess, lpBaseAddress,len,MEM_COMMIT); CloseHandle(hProcess); Abort(); end; Form1.Caption:='写入内存成功!'; pLoadLibrary:=GetProcAddress(GetModuleHandle('kernel32.dll'),'LoadLibraryA'); if pLoadLibrary=nil then begin Form1.Caption:='获取输出库函数地址失败!'; Abort(); end; Form1.Caption:='获取输出库函数地址成功!'; hThread:=CreateRemoteThread(hProcess,nil,0,pLoadLibrary, lpBaseAddress,0,lpThreadId); if hThread=0 then begin Form1.Caption:='创建远程线程失败!'; end; Form1.Caption:='创建远程线程成功!'; WaitForSingleObject(hThread,INFINITE); VirtualFreeEx(hProcess, lpBaseAddress,len,MEM_COMMIT); CloseHandle(hThread); CloseHandle(hProcess); end; procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); var dwProcessId:DWORD; begin dwProcessId:=StrToInt(Trim(item.Caption)); hProcess:=OpenProcess(PROCESS_ALL_ACCESS ,False, dwProcessId); if hProcess=0 then begin Form1.Caption:='打开进程失败!'; CloseHandle(hProcess); Abort(); end; Form1.Caption:='打开进程成功!'; end; end. {下面是所用到的函数的详细说明:} {function VirtualAllocEx(hProcess: THandle; lpAddress: Pointer; dwSize, flAllocationType: DWORD; flProtect: DWORD): Pointer; stdcall;} {VirtualAllocEx 函数的作用是在指定进程的虚拟空间保留或提交内存区域, } { 除非指定MEM_RESET参数,否则将该内存区域置0。 } {参数说明: } {hProcess: 申请内存所在的进程句柄。 } {lpAddress:保留页面的内存地址;一般用nil自动分配 。 } {dwSize:欲分配的内存大小,字节单位;注意实际分 配的内存大小是页内存大小的整数倍} {flAllocationType:可取下面表1的值 } {flProtect: 可取下面表2的值 } {表1:} {MEM_COMMIT: 为特定的页面区域分配内存中或磁盘的页面文件中的物理存储 } {MEM_PHYSICAL : 分配物理内存(仅用于地址窗口扩展内存) } {MEM_RESERVE: 保留进程的虚拟地址空间,而不分配任何物理存储。 } { 保留页面可通过继续调用VirtualAlloc()而被占用 } {MEM_RESET : 指明在内存中由参数lpAddress和dwSize指定的数据无效 } {MEM_TOP_DOWN: 在尽可能高的地址上分配内存(Windows 98忽略此标志) } {MEM_WRITE_WATCH:必须与MEM_RESERVE一起指定,使系统跟踪那些被写入 } { 分配区域的页面(仅针对Windows 98) } {表2:} {PAGE_READONLY: 该区域为只读。如果应用程序试图访问区域中的页的时候, } { 将会被拒绝访问PAGE_READWRITE 区域可被应用程序读写 } {PAGE_EXECUTE: 区域包含可被系统执行的代码。试图读写该区域的操作将被拒绝。} {PAGE_EXECUTE_READ : 区域包含可执行代码,应用程序可以读该区域。 } {PAGE_EXECUTE_READWRITE: 区域包含可执行代码,应用程序可以读写该区域。 } {PAGE_GUARD: 区域第一次被访问时进入一个STATUS_GUARD_PAGE异常, } { 这个标志要和其他保护标志合并使用,表明区域被第一次访问的权限 } {PAGE_NOACCESS: 任何访问该区域的操作将被拒绝 } {PAGE_NOCACHE: RAM中的页映射到该区域时将不会被微处理器缓存(cached) } {********************************优伤的分隔线******************************} {function OpenProcess(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwProcessId: DWORD): THandle; stdcall;} {OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。} {参数说明:} {dwDesiredAccess是访问进程的权限。见下面表3} {bInheritHandle 是句柄是否继承进程属性。 } {dwProcessId 是进程ID。 } {表3} {PROCESS_ALL_ACCESS 所有能获得的权限 } {PROCESS_CREATE_PROCESS 需要创建一个进程 } {PROCESS_CREATE_THREAD 需要创建一个线程 } {PROCESS_DUP_HANDLE 重复使用DuplicateHandle句柄 } {PROCESS_QUERY_INFORMATION 获得进程信息的权限,如它的退出代码、优先级} {PROCESS_QUERY_LIMITED_INFORMATION 获得某些信息的权限,如果获得了 } { PROCESS_QUERY_INFORMATION, } {也拥有PROCESS_QUERY_LIMITED_INFORMATION权限 } {PROCESS_SET_INFORMATION 设置某些信息的权限,如进程优先级69 } {PROCESS_SET_QUOTA 设置内存限制的权限, 使用SetProcessWorkingSetSize } {PROCESS_SUSPEND_RESUME 暂停或恢复进程的权限 } {PROCESS_TERMINATE 终止一个进程的权限,使用TerminateProcess } {PROCESS_VM_OPERATION 操作进程内存空间的权限 (可用VirtualProtectEx和WriteProcessMemory)} {PROCESS_VM_READ 读取进程内存空间的权限,可使用ReadProcessMemory } {PROCESS_VM_WRITE 读取进程内存空间的权限,可使用WriteProcessMemory} {SYNCHRONIZE 等待进程终止 } {********************************性感的分隔线******************************} {function CreateToolhelp32Snapshot(dwFlags, th32ProcessID: DWORD): THandle; } {CreateToolhelp32Snapshot函数功能:函数为指定的进程、进程使用的堆[HEAP]、 } {模块[MODULE]、线程[THREAD])建立一个快照[snapshot]。 } {参数1说明:dwFlags } {TH32CS_INHERIT 声明快照句柄是可继承的。 } {TH32CS_SNAPALL 在快照中包含系统中所有的进程和线程。 } {TH32CS_SNAPHEAPLIST 在快照中包含在th32ProcessID中指定的进程的所有的堆。 } {TH32CS_SNAPMODULE 在快照中包含在th32ProcessID中指定的进程的所有的模块。 } {TH32CS_SNAPPROCESS 在快照中包含系统中所有的进程。 } {TH32CS_SNAPTHREAD 在快照中包含系统中所有的线程。 } {参数2说明:th32ProcessID } {指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了 } {TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,} {所有的进程都会被快照。 } {返回值: } {调用成功,返回快照的句柄,调用失败,返回0。 } {********************************优美的分隔线******************************} {PROCESSENTRY32结构} {tagPROCESSENTRY32 = packed record dwSize: DWORD; 结构的大小 cntUsage: DWORD; 此进程的引用计数 th32ProcessID: DWORD; 进程ID th32DefaultHeapID: DWORD; 进程默认堆 th32ModuleID: DWORD; 进程模块IDThis cntThreads: DWORD; 此进程开启的线程计数 th32ParentProcessID: DWORD; 父进程的ID pcPriClassBase: Longint; 线程优先权 dwFlags: DWORD; szExeFile: array[0..MAX_PATH - 1] of Char; 进程全名 end;} {********************************优美的分隔线******************************} {function Process32First(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; } {Process32First 是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot() } {获得当前运行进程的快照后,我们可以利用process32First函数来获得第一个进程的句柄 } {参数1说明:hSnapshot } {CreateToolhelp32Snapshot获取进程快照的句柄 } {参数2说明:lppe } {TProcessEntry32创建的结构体 } {返回值: } {调用成功,返回True,调用失败,返回False。 } {********************************优美的分隔线******************************} {function Process32Next(hSnapshot: THandle; var lppe: TProcessEntry32): BOOL; } {Process32Next是一个进程获取函数,当我们利用函数CreateToolhelp32Snapshot() } {获得当前运行进程的快照后,我们可以利用Process32Next函数来获得下一个进程的句柄 } {参数1说明:hSnapshot } {CreateToolhelp32Snapshot获取进程快照的句柄 } {参数2说明:lppe } {TProcessEntry32创建的结构体 } {返回值: } {调用成功,返回True,调用失败,返回False。 } {********************************优美的分隔线******************************} {function WriteProcessMemory(hProcess: THandle; const lpBaseAddress: Pointer; lpBuffer: Pointer;nSize:DWORD; var lpNumberOfBytesWritten: DWORD):BOOL;stdcall;} {WriteProcessMemory是一个写内存函数 } {参数说明: } {hProcess: 进程的句柄 } {lpBaseAddress: 写入进程的位置(地址) } {lpBuffer: 数据当前存放地址 } {nSize: 数据的长度 } {lpNumberOfBytesWritten:实际数据的长度 } {********************************优美的分隔线******************************} {function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall; } {LoadLibrary函数载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦 } {载入,即可访问库内保存的资源。 } {参数说明: } {lpLibFileName:指定要载入的动态链接库的名称。 } {返回值: } {成功则返回库模块的句柄,零表示失败。 } {********************************优美的分隔线******************************} {function CreateRemoteThread(hProcess: THandle; lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;} {CreateRemoteThread函数在远程进程中创建线程 } {参数说明: } {hProcess:进程句柄 } {lpThreadAttributes:线程安全描述字,指向SECURITY_ATTRIBUTES结构的指针 } {dwStackSize:线程栈大小,以字节表示 } {lpStartAddress:一个LPTHREAD_START_ROUTINE类型的指针,指向在远程进程中执行的函数地址} {lpParameter:传入参数 } {dwCreationFlags:创建线程的其它标志 } {lpThreadId:线程身份标志,如果为NULL,则不返回 } {返回值: } {成功返回新线程句柄,失败返回nil。 } {********************************优美的分隔线******************************} {function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall;} {WaitForSingleObject函数用来检测hHandle事件的信号状态, } {当函数的执行时间超过dwMilliseconds就返回, } {但如果参数dwMilliseconds为INFINITE时函数将直到相应时间 } {事件变成有信号状态才返回,否则就一直等待下去, } {直到WaitForSingleObject有返回值才执行后面的代码。 } {参数说明: } {hHandle:同步对象的句柄 } {dwMilliseconds:超时间隔,单位为毫秒,为INFINITE时超时是无限的 } {********************************优美的分隔线******************************} {function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall;} {GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。 } {参数说明: } {hModule:DLL模块句柄 } {lpProcName:函数名 } {返回值: } {如果函数调用成功,返回值是DLL中的输出函数地址。 如果函数调用失败,返回值是nil } {********************************优美的分隔线******************************} {function GetModuleHandle(lpModuleName: PChar): HMODULE; stdcall; } {GetModuleHandle函数获取一个应用程序或动态链接库的模块句柄 } {参数说明: } {lpModuleName:模块名,这通常是与模块的文件名相同的一个名字 } {返回值: } {如执行成功成功,则返回模块句柄 }
[ 本帖最后由 ioriliao 于 2010-10-7 15:05 编辑 ]