问题
My application is an x64 Windows console app that needs to inject itself into another running process. When executed from the command line, you enter the PID of the process you want to inject into as a command line parameter.
Within the context of a thread running under a parent process, I'm able to work with String variables, but I'm having difficulty trying to figure out how to convert an Integer to a String in Delphi. Everything I've tried to convert from Integer to String has the effect of crashing the parent process. I understand that standard Delphi RTL commands are not going to work, and that I need to use WINAPI functions.
Here is a list of some of the commands I've tried:
a. IntToStr(int) crashes parent process;
b. itoa(src, dst, radix) crashes parent process;
c. strcpy(dst, src) crashes parent process;
I've included a working snippet of code that compiles in Delphi RAD Studio RIO 10.3.2. Be sure to set the Target Platform as a Windows-64-bit. As-is, the program simply injects into a process and displays a MessageBox. I've included and commented out the commands that crash the parent process.
In this sample program, I'm attempting to display the PID of the running process which was determined using GetCurrentProcessId(), which returns the PID as an Integer. The challenge is trying to convert the variable 'x' to a string variable 's'. I've also tried converting 'x' into a PAnsiChar variable using itoa(), which fails.
I anticipate that my issue is likely that I'm not loading the correct Windows library, or that I'm not defining the WINAPI function that I'm trying to use.
Any assistance would be greatly appreciated, as I'm stuck and can't move forward until I get past this hurdle.
program Inject;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Variants,
System.Classes,
Winapi.Windows,
Winapi.Messages,
ShellAPI,
System.Win.crtl,
shlobj;
var
ClassName: string;
ProcessHandle: Thandle;
Active : Integer;
PID : integer;
Module, NewModule: Pointer;
Size: SIZE_T;
BytesWritten: SIZE_T;
TID: DWORD;
procedure Main;
var
x : Integer;
s : string;
p : PAnsiChar;
begin
LoadLibrary('kernel32.dll');
LoadLibrary('user32.dll');
LoadLibrary('msvcrt.dll');
LoadLibrary('win32.dll');
x := GetCurrentProcessId;
{ This command crashes the parent process }
// s := IntToStr(x);
{ This command crashes the parent process }
// itoa(x, p, 10);
{ This command crashes the parent process }
strcpy(P, PAnsiChar(IntToStr(x)));
{ A standard Message Box works }
MessageBox(0, 'This Message Box produced by Thread running under Parent Process', 'Process ID', 0);
{ This Message Box crashes the parent process }
// MessageBox(0, PWideChar(IntToStr(x)), 'Process ID', 0);
ExitThread(0);
end;
begin
try
if (ParamCount() > 0) then
begin
PID := StrToInt(ParamStr(1));
ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
Module := Pointer(GetModuleHandle(nil));
Size := PImageOptionalHeader64(Pointer(integer(Module) + PImageDosHeader(Module)._lfanew + SizeOf(dword) + SizeOf(TImageFileHeader))).SizeOfImage;
VirtualFreeEx(ProcessHandle, Module, 0, MEM_RELEASE);
NewModule := VirtualAllocEx(ProcessHandle, Module, Size, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(ProcessHandle, NewModule, Module, Size, BytesWritten);
CreateRemoteThread(ProcessHandle, nil, 0, @Main, Module, 0, TID);
WaitForSingleObject(ProcessHandle, 1000);
end
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
回答1:
In your Main()
procedure, when calling itoa()
or strcpy()
, your p
variable is an uninitialized pointer, it doesn't point to any valid memory. You need to allocate memory to write to, eg:
procedure Main;
var
x : Integer;
str : array[0..12] of AnsiChar;
begin
LoadLibrary('kernel32.dll');
LoadLibrary('user32.dll');
LoadLibrary('msvcrt.dll');
LoadLibrary('win32.dll');
x := GetCurrentProcessId;
itoa(x, str, 10);
MessageBoxA(0, str, 'Process ID', 0);
ExitThread(0);
end;
In the case of strcpy()
, you have the additional problem that IntToStr()
in Delphi 2009+ returns a UnicodeString
, not an AnsiString
, so your typecast to PAnsiChar
is wrong anyway.
Alternatively, look at the Win32 wsprintfA() function in user32.dll
:
procedure Main;
var
x : Integer;
str : array[0..12] of AnsiChar;
begin
LoadLibrary('kernel32.dll');
LoadLibrary('user32.dll');
LoadLibrary('msvcrt.dll');
LoadLibrary('win32.dll');
x := GetCurrentProcessId;
wsprintfA(str, '%d', x);
MessageBoxA(0, str, 'Process ID', 0);
ExitThread(0);
end;
来源:https://stackoverflow.com/questions/59438440/converting-integer-to-string-crashes-injected-parent-process-delphi