Vamos a dar un empujoncito al tema. He escrito una función un poco a lo bruto para cambiar una cadena en un proceso. He de aclarar que está escrito en delphi7, que se compila para 32bits, esto quiere decir que no se pueden atacar de esta forma procesos de 64bits. Lo he probado en winXP y en Win10:
Código Delphi
[-]
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TLHelp32;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Label2: TLabel;
Label3: TLabel;
Edit3: TEdit;
procedure Button1Click(Sender: TObject);
private
public
end;
function _wcsnicmp(wstr1, wstr2: PWCHAR; Size: integer): Integer; cdecl external 'crtdll';
function wcslen(wstr: PWCHAR): Integer; cdecl external 'crtdll';
var
Form1: TForm1;
implementation
{$R *.dfm}
function EnablePrivilege(name: String; Enable: boolean = true): boolean;
var
hToken: Cardinal;
priv: TOKEN_PRIVILEGES;
begin
priv.PrivilegeCount:= 1;
priv.Privileges[0].Attributes:= 0;
if Enable then priv.Privileges[0].Attributes:= SE_PRIVILEGE_ENABLED;
LookupPrivilegeValue(nil, PCHAR(name), priv.Privileges[0].Luid);
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken);
AdjustTokenPrivileges (hToken, FALSE, priv, sizeof(priv), nil, PDWORD(nil)^);
Result:= (GetLastError = ERROR_SUCCESS);
CloseHandle (hToken);
end;
function RemoteReplaceString(PID: DWORD; Str, NewStr: PWCHAR): BOOL;
const
nBytes = $16000;
var
hProc: THANDLE;
n, i, T, Len, nBytesRead: DWORD;
Buffer, RemoteAddr: PBYTE;
bi: MEMORY_BASIC_INFORMATION;
begin
Result:= false;
hProc:= OpenProcess(PROCESS_ALL_ACCESS, false, PID);
Len:= wcslen(Str) * sizeof(WCHAR);
GetMem(Buffer, nBytes);
EnablePrivilege('SeDebugPrivilege');
for n:= 0 to $1000 do
begin
RemoteAddr:= PBYTE(n*nBytes-Len);
ReadProcessMemory(hProc, RemoteAddr, Buffer, nBytes, nBytesRead);
if nBytesRead > 0 then
begin
T:= nBytesRead - (nBytesRead mod wcslen(Str));
i:= 0;
while i <= T do
begin
if _wcsnicmp(PWCHAR(DWORD(Buffer)+i), Str, wcslen(Str)) = 0 then
begin
if WriteProcessMemory(hProc, pointer(DWORD(RemoteAddr) + i), NewStr, Len, nBytesRead) then
i:= i + wcslen(Str);
end;
inc(i);
end;
end;
end;
FreeMem(Buffer);
CloseHandle(hProc);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
proc: TProcessEntry32;
hSysSnapshot: THandle;
begin
proc.dwSize := SizeOf(TProcessEntry32);
hSysSnapshot:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSysSnapshot <> INVALID_HANDLE_VALUE) and Process32First(hSysSnapshot, proc) then
begin
repeat
if SameText(String(proc.szExeFile), Edit1.Text) then
RemoteReplaceString(proc.th32ProcessID, PWCHAR(WideString(Edit2.Text)), PWCHAR(WideString(Edit3.Text)));
until not (Process32Next(hSysSnapshot, proc));
end;
CloseHandle(hSysSnapshot);
end;
end.
He de comentar lo siguiente:
1- Las cadenas de un proceso en memoria deben tratarse como UNICODE
2- He usado funciones "C" de la librería crtdll.dll que trae Windows como parte del S.O. para faciñitar la búsquede de cadenas a bajo nivel
-
wcslen devuelve el número de caracteres de una cadena tipo WCHAR
- _
wcsnicmp compara una cadena WCHAR con otra en una longitud máxima dada y sin ser sensible a mayúsculas/minúsculas
3- Un código para 32bits no puede leer la memoria de un proceso 64 bits sin más, se precisa un driver o trucos especiales, esto es debido a la incompatibilidad de los punteros que definen el rango de direcciones que son capaces de direccionar.
4- No se puede sustituir una cadena por otra de mayor longitud.
Espero aclarar alguna duda a
deliriun.
Saludos.