花了一个下午翻了MSDN,写了这个例子,为了安全,我用Delphi建了个什么也没有作的程序PRjzzhost.exe,将它用作被注入的宿主进程.
写了一个TestDll.Dll,里面只有一个Log函数,用来在文件Test.Txt中输出信息.最重要的一个程序project1.exe是用来注入的.
测试环境:windowsserver2003+delphi7.0
程序很简单,高手就不用看了.废话不说了,看代码吧!
测试用的TestDll.Dll源代码(它将被注入到prjzzhost.exe中去):
程序代码libraryTestDll;
uses
SysUtils,
System,
windows,
Classes;
procedureLog(s:PChar);stdcall;
var
F:TextFile;
begin
assignfile(f,'Test.txt');
iffileexists('Test.txt')thenappend(f)
elserewrite(f);
writeln(f,s);
closefile(f);
end;
procedureDllEntryPoint(dwReason:DWord);
begin
casedwReasonof
DLL_PROCESS_ATTACH:
Log('dllprocessAttach');
DLL_PROCESS_DETACH:
Log('dllprocessDetach');
DLL_THREAD_ATTACH:
Log('dllthreadAttach');
DLL_THREAD_DETACH:
Log('dllthreadDetach');
end;
end;
exports
Log;
begin
DllProc:=@DllEntryPoint;
DllEntryPoint(DLL_PROCESS_ATTACH);
end.
被注入的宿主进程prjzzhost.exe(它什么也没有作,好无辜哦:),这里就不给出代码了,因为太简单了,哈哈.
最后,最重要的来了:
project1.exe的源代码:
程序代码unitUnit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,tlhelp32;
type
TLog=procedure(s:PChar);stdcall;
TServiceMain=procedure(argc:Integer;VARargv:pchar);stdcall;
EDLLLoadError=class(Exception);
TForm1=class(TForm)
Button3:TButton;
procedureButton3Click(Sender:TObject);
private
{Privatedeclarations}
public
{Publicdeclarations}
end;
var
Form1:TForm1;
implementation
{$R*.dfm}
{列举进程}
procedureGetMyProcessID(constAFilename:string;constPathMatch:Boolean;varProcessID:DWORD);
var
lppe:TProcessEntry32;
SsHandle:Thandle;
FoundAProc,FoundOK:boolean;
begin
ProcessID:=0;
{创建系统快照}
SsHandle:=CreateToolHelp32SnapShot(TH32CS_SnapProcess,0);
{取得快照中的第一个进程}
{一定要设置结构的大小,否则将返回False}
lppe.dwSize:=sizeof(TProcessEntry32);
FoundAProc:=Process32First(Sshandle,lppe);
whileFoundAProcdo
begin
{进行匹配}
ifPathMatchthen
FoundOK:=AnsiStricomp(lppe.szExefile,PChar(AFilename))=0
else
FoundOK:=AnsiStricomp(PChar(ExtractFilename(lppe.szExefile)),PChar(ExtractFilename(AFilename)))=0;
ifFoundOKthen
begin
ProcessID:=lppe.th32ProcessID;
break;
end;
{未找到,继续下一个进程}
FoundAProc:=Process32Next(SsHandle,lppe);
end;
CloseHandle(SsHandle);
end;
{设置权限}
functionEnabledDebugPrivilege(constEnabled:Boolean):Boolean;
var
hTk:THandle;{打开令牌句柄}
rtnTemp:Dword;{调整权限时返回的值}
TokenPri:TOKEN_PRIVILEGES;
const
SE_DEBUG='SeDebugPrivilege';{查询值}
begin
Result:=False;
{获取进程令牌句柄,设置权限}
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,hTk))then
begin
TokenPri.PrivilegeCount:=1;
{获取Luid值}
LookupPrivilegeValue(nil,SE_DEBUG,TokenPri.Privileges[0].Luid);
ifEnabledthen
TokenPri.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED
else
TokenPri.Privileges[0].Attributes:=0;
rtnTemp:=0;
{设置新的权限}
AdjustTokenPrivileges(hTk,False,TokenPri,sizeof(TokenPri),nil,rtnTemp);
Result:=GetLastError=ERROR_SUCCESS;
CloseHandle(hTk);
end;
end;
{调试函数}
procedureOutPutText(varCH:PChar);
var
FileHandle:TextFile;
Begin
AssignFile(FileHandle,'zztest.txt');
Append(FileHandle);
Writeln(FileHandle,CH);
Flush(FileHandle);
CloseFile(FileHandle);
END;
{注入远程进程}
functionInjectTo(constHost,Guest:string;constPID:DWORD=0):DWORD;
var
{被注入的进程句柄,进程ID}
hRemoteProcess:THandle;
dwRemoteProcessId:DWORD;
{写入远程进程的内容大小}
memSize:DWORD;
{写入到远程进程后的地址}
pszLibFileRemote:Pointer;
iReturnCode:Boolean;
TempVar:DWORD;
{指向函数LoadLibraryW的地址}
pfnStartAddr:TFNThreadStartRoutine;
{dll全路径,需要写到远程进程的内存中去}
pszLibAFilename:PwideChar;
begin
Result:=0;
{设置权限}
EnabledDebugPrivilege(True);
{为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2}
Getmem(pszLibAFilename,Length(Guest)*2+1);
StringToWideChar(Guest,pszLibAFilename,Length(Guest)*2+1);
{获取进程ID}
ifPID>0then
dwRemoteProcessID:=PID
else
GetMyProcessID(Host,False,dwRemoteProcessID);
{取得远程进程句柄,具有写入权限}
hRemoteProcess:=OpenProcess(PROCESS_CREATE_THREAD+{允许远程创建线程}
PROCESS_VM_OperaTION+{允许远程VM操作}
PROCESS_VM_WRITE,{允许远程VM写}
FALSE,dwRemoteProcessId);
{用函数VirtualAllocex在远程进程分配空间,并用WriteProcessMemory中写入dll路径}
memSize:=(1+lstrlenW(pszLibAFilename))*sizeof(WCHAR);
pszLibFileRemote:=PWIDESTRING(VirtualAllocEx(hRemoteProcess,nil,memSize,MEM_COMMIT,PAGE_READWRITE));
TempVar:=0;
iReturnCode:=WriteProcessMemory(hRemoteProcess,pszLibFileRemote,pszLibAFilename,memSize,TempVar);
ifiReturnCodethen
begin
pfnStartAddr:=GetProcAddress(GetModuleHandle('Kernel32'),'LoadLibraryW');
TempVar:=0;
{在远程进程中启动dll}
Result:=CreateRemoteThread(hRemoteProcess,nil,0,pfnStartAddr,pszLibFileRemote,0,TempVar);
end;
{释放内存空间}
Freemem(pszLibAFilename);
end;
{测试}
procedureTForm1.Button3Click(Sender:TObject);
begin
InjectTo('prjzzhost.exe',extractfilepath(paramstr(0))+'TestDll.dll');
end;
end.
代码中并没有考虑dll被载入后的善后处理,请不要使用系统进程进行测试,以免发生意外.