Converting Integer to String crashes Injected Parent Process [Delphi]

怎甘沉沦 提交于 2020-01-24 18:30:38

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!