ObjectPhysicalMemoryDeviceName = '"Device"Physicalmemory'; NTDLL = 'ntdll.dll'; var ZwOpenSection: TZwOpenSection; zwClose:TzwClose; RtlInitUnicodeString: TRtlInitUnicodeString; hNtdll:HMODULE; function ReadOrWritePhyMem(ReadOnly:Boolean; Address, Length:DWORD; buffer:Pointer ):boolean; function ReadOrWriteProcessMem(ReadOrWrite:Boolean; Pid, Address, Length:DWORD; buffer:Pointer ):Boolean; implementation
//加载NT.dll并找到函数 function LocateNtdllEntryPoints: BOOLEAN; begin Result:=false; hNtDll:=GetModuleHandle(NTDLL); if hNTdll=0 then Exit;
if not Assigned(ZwOpenSection) then ZwOpenSection:=GetProcAddress(hNtdll,'ZwOpenSection'); if not Assigned(ZwClose) then ZwClose:=GetProcAddress(hNtDll,'ZwClose'); if Not Assigned(RtlInitUnicodeString) then RtlInitUnicodeString:=GetProcAddress(hNtDll,'RtlInitUnicodeString');
Result:=true; end;
//设置物理内存为可写 function SetPhyMemCanBeWrite(hSection:THandle):Boolean; var pDacl,pNewDacl:PACL; pSD:PPSECURITY_DESCRIPTOR; dwRes:Cardinal; ea:EXPLICIT_ACCESS_A; label CleanUp; begin result:=false; pDacl:=nil; pNewDacl:=nil; pSD:=nil;
if dwRes<>ERROR_SUCCESS then begin if pSD<>nil then LocalFree(Cardinal(pSD^)); if pNewDacl<>nil then LocalFree(Cardinal(pSD^)); raise Exception.Create('不能获得物理内存的安全信息!') end;
if dwRes = ERROR_SUCCESS then begin if pSD<>nil then LocalFree(Cardinal(pSD^)); if pNewDacl<>nil then LocalFree(Cardinal(pSD^)); Result:=true; end; end;
//打开物理内存 Readon_ly=false时可以写,若失败返回 0 function OpenPhyMem(ReadOnly:Boolean):THandle; var PhyMemName:TUnicodestring;//物理内存名 wsPhyMemName:WideString; attrib:TObjectAttributes; SectionAttrib:Integer; status:NTSTATUS; hPhyMem:THandle; begin result:=0;
if status<0 then begin Exit; //失败,则推出 end; Result:=hPhyMem; end;
//影射物理内存为本进程的虚拟内存 function MapPhyMem(ReadOnly:Boolean; //是否只读 PhyMem:THandle; //物理内存句柄 Address, //起始地址 Length:DWORD; //长度 var VirtualAddress:Pchar //本地虚拟地址 ):Boolean; //成功返回true var Access:Cardinal; begin result:=false;
if ReadOnly then Access:=FILE_MAP_READ else Access:= FILE_MAP_READ or FILE_MAP_WRITE;
//返回值VirtualAddress自动按页对齐,需要改正?? Inc(DWORD(VirtualAddress),Access mod $1000);
result:=true; end;
//取消影射 procedure UnMapPhyMem(Address:pointer); begin UnmapViewOfFile(Address); end;
//读写物理内存! function ReadOrWritePhyMem(ReadOnly:Boolean; //是否只读 Address, Length:DWORD; buffer:Pointer ):boolean; var hPhyMem:THandle; VAddress:Pchar; begin result:=false;
if not Assigned(ZwOpenSection) then Exit;
hPhyMem:=OpenPhyMem(ReadOnly);
if hPhyMem=0 then Exit;
if not MapPhyMem(ReadOnly,hPhyMem,Address,length,vaddress) then Exit;
try if ReadOnly then Move(vaddress^,buffer^,length) else Move(buffer^,vaddress^,length); result:=true; Except on e:Exception do begin MessageDlg('缓中区长度不足或内存跨段。'+#$D+ '每个内存段为4K的整数倍,每次读写不能跨越多个不同的内存段。', mtError, [mbok],0); end; end; UnMapPhyMem(VAddress); ZwClose(hPhyMem); end;
//读写其它进程内存 function ReadOrWriteProcessMem(ReadOrWrite:Boolean;Pid:Cardinal;Address,Length:DWORD;buffer:Pointer):Boolean; var hProcess:THandle; ReadLength:Cardinal; mbi:TMemoryBasicInformation; OldProtect:DWORD; begin Result:=false; if ReadOrWrite then //如果是读取 begin hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,Pid); //打开进程
if (not ReadProcessMemory(hProcess, Pointer(Address), buffer, Length, ReadLength)) or (Length<>ReadLength) then begin // ShowMessage(IntToStr(GetlastError)); CloseHandle(hProcess); Exit; end;
end else //如果是写入 begin hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,Pid);