• XSS.stack #1 – первый литературный журнал от юзеров форума

Перенаправление ввода-вывода, Win32Api

в коде может быть что угодно, любую вещь надо дебажить - т.е. запустить процесс, приаттачиться и посмотреть, какая именно апи в дочернем процессе дает такой эксепшн. И какие хендлы реально передаются.
Для дебаггера какие-то дополнительные знания наверно нужны? Или там все "интуитивно понятно"?
 
Вот скриншот окна деббагера, исключение на строке:

Код:
InputText(input_text);
        input_text := '';

в ntdll.dll

После выполнения:
procedure InputText(s: string);
var
BytesCount: Cardinal;
buf: array [0..4096] of Char;
begin
if Length(s) < 4090 then
begin
ZeroMemory(@buf, SizeOf(buf));
StrPCopy(buf, s + #13#10); //
WriteFile(hPipeInputWrite, buf, Length(s) + 2, BytesCount, nil);
end;
end;
 

Вложения

  • 2024-01-23_10-06-53.png
    2024-01-23_10-06-53.png
    17.4 КБ · Просмотры: 36
  • 2024-01-23_10-07-14.png
    2024-01-23_10-07-14.png
    30.8 КБ · Просмотры: 36
Последнее редактирование:
Проще в исходниках разобраться, чем дебажить(кем надо быть вообще)

Перевел сорец RemoteShell на православный паскаль
Код:
procedure CMD.createChildProcess(const path: string);
var
  siStartInfo: TStartupInfoA;
  piProcInfo: TProcessInformation;
  bSuccess: Boolean;
begin
  ZeroMemory(@piProcInfo, SizeOf(TProcessInformation));
  ZeroMemory(@siStartInfo, SizeOf(TStartupInfoA));
  siStartInfo.cb := SizeOf(TStartupInfoA);
  siStartInfo.hStdError := g_hChildStd_OUT_Wr;
  siStartInfo.hStdOutput := g_hChildStd_OUT_Wr;
  siStartInfo.hStdInput := g_hChildStd_IN_Rd;
  siStartInfo.dwFlags := siStartInfo.dwFlags or STARTF_USESTDHANDLES;

  bSuccess := CreateProcessA(PAnsiChar(path), nil, nil, nil, True, CREATE_NO_WINDOW, nil, nil, @siStartInfo, @piProcInfo);
  if not bSuccess then
    Exit
  else
  begin
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
  end;

  g_hChildProcess := piProcInfo.hProcess;
  g_hChildThread := piProcInfo.hThread;
end;
Код:
procedure CMD.writeCMD(var command: string);
var
  dwWritten: DWORD;
begin
  if RemoteShell.cmdOpen then
  begin
    command := command + #10;
    WriteFile(g_hChildStd_IN_Wr, PChar(command)^, Length(command), dwWritten, nil);
  end;
end;
По идее в readCMD то же самое, небольшой анал-карнавал с intBytesAvailable:
Код:
function CMD.readCMD: string;
var
  bytesAvailable, bytesRead, intBytesAvailable: DWORD;
  buffer: array[0..127] of Char;
  output: string;
begin
  if RemoteShell.cmdOpen then
  begin
    PeekNamedPipe(g_hChildStd_OUT_Rd, nil, 0, nil, @bytesAvailable, nil);
    if bytesAvailable <= 0 then
      Exit('');
 
    intBytesAvailable := bytesAvailable;
    output := '';
    while intBytesAvailable > 0 do
    begin
      ReadFile(g_hChildStd_OUT_Rd, buffer, 127, bytesRead, nil);
      buffer[bytesRead] := #0;
      output := output + string(buffer);
      Dec(intBytesAvailable, bytesRead);
      if intBytesAvailable <= 0 then
        intBytesAvailable := 0;
      ZeroMemory(@buffer, SizeOf(buffer));
    end;
    Result := output;
  end
  else
    Result := '';
end;
Здесь есть SetHandleInformation, в отличии от моего решения:
Код:
constructor CMD.Create(const cmd: string);
begin
  saAttr.nLength := SizeOf(TSecurityAttributes);
  saAttr.bInheritHandle := True;
  saAttr.lpSecurityDescriptor := nil;

  if CreatePipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr, @saAttr, 0) and
    SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) and
    CreatePipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr, @saAttr, 0) then
    SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);

  createChildProcess(cmd);
end;

Изначально инициируются в NULL:
Код:
//variables
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
 
Последнее редактирование:
Добавил новое ебобо SetHandleInformation и HANDLE_FLAG_INHERIT в свой сорец - так же вылетает исключение
Код:
   if CreatePipe(hPipeOutputRead, hPipeOutputWrite, @SecurityAttributes, 0) then
    SetHandleInformation(hPipeOutputRead, HANDLE_FLAG_INHERIT, 0);

   if CreatePipe(hPipeInputRead, hPipeInputWrite, @SecurityAttributes, 0) then
    SetHandleInformation(hPipeInputWrite, HANDLE_FLAG_INHERIT, 0);

Стою на дамаге, в лыжи обутый...)​

 
Последнее редактирование:
Почти не шарю в делфи или паскале но так - мысли

ReadFile(g_hChildStd_OUT_Rd, buffer, 127, bytesRead, nil);
bytesRead должен быть поинтером, -> ReadFile(g_hChildStd_OUT_Rd, buffer, 127, @bytesRead, nil);
[out, optional] lpNumberOfBytesRead

Указатель на переменную, которая получает количество считываемых байтов при использовании синхронного параметра hFile . ReadFile устанавливает это значение равным нулю перед выполнением какой-либо работы или проверки ошибок. Используйте значение NULL для этого параметра, если это асинхронная операция, чтобы избежать потенциально ошибочных результатов.
То есть как я это вижу:

bytesRead переменная инициализируется каким-то мусором там может быть 0 а может быть 12345
ReadFile вместо адреса переменной получает её значение - то есть в теории туда может попасть 12345 интерпретируемый как адрес - куда запишется значение числа прочитанных байт и будет access violation
 
Последнее редактирование:
чем дебажить(кем надо быть вообще)
Если ты так реально считаешь то далеко в кодинге не уйдёшь - дебажить надо уметь
 
В паскале можно передать буфер в WriteFile/ReadFile в виде
Код:
ReadFile(hPipeOutputRead, buf, Length(buf), BytesCount, nil);
WriteFile(hPipeInputWrite, buf, Length(buf), BytesCount, nil);
Код:
function WriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD;
  var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
{$EXTERNALSYM WriteFile}

function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD;
  var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
{$EXTERNALSYM ReadFile}
то есть в теории туда может попасть 12345 интерпретируемый как адрес - куда запишется значение числа прочитанных байт и будет access violation

В обоих случаях перед WriteFile/ReadFile вызывается ZeroMemory(@buf, SizeOf(buf));

Код:
Если ты так реально считаешь то далеко в кодинге не уйдёшь - дебажить надо уметь
Это прописная истина, секрет, который всем и так известен
 
Как можно писать код и не уметь его отлаживать? Очередной говнокод на выходе? Если уж совсем траблы с отладчиком на уровне самого "программиста", то можно использовать SEH/VEH в своем коде.
 
Как можно писать код и не уметь его отлаживать? Очередной говнокод на выходе? Если уж совсем траблы с отладчиком на уровне самого "программиста", то можно использовать SEH/VEH в своем коде.
А ты когда учился писать код и программирование в целом, у тебя не было ошибок? Если ты вообще изучал программирование. Зачем человеку твоя скудная ненужная информацию.
 
Вот, как это можно сделать по-взрослому, без лишних телодвижений, используя Python
Эта реализация мне нужна чтобы запускать _из delphi_ скрипты на python.

Короче, я понел в чем секрет полишинеля. Теперь работает без External exception.

.Сначала создаем процесс:
Код:
function StartProcess(current_file: string): bool;
var
  s: string;
  StartupInfo: TStartupInfo;
  ProcessInformation: TProcessInformation;
  SecurityAttributes: TSecurityAttributes;
begin
  Result := true;

  Writeln('Process started.');

  ZeroMemory(@StartupInfo, SizeOf(TStartupInfo));
  ZeroMemory(@ProcessInformation, SizeOf(TProcessInformation));

  ZeroMemory(@SecurityAttributes, SizeOf(TSecurityAttributes));
 
  SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
  SecurityAttributes.lpSecurityDescriptor := nil;
  SecurityAttributes.bInheritHandle := True;

  CreatePipe(hPipeInputRead, hPipeInputWrite, @SecurityAttributes, 0);
  CreatePipe(hPipeOutputRead, hPipeOutputWrite, @SecurityAttributes, 0);

  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.hStdInput := hPipeInputRead;
  StartupInfo.hStdOutput := hPipeOutputWrite;
  StartupInfo.hStdError := hPipeOutputWrite;

  s := format('python "%s"', [current_file]);
 
  if CreateProcess(nil, PChar(s), nil, nil,
                   true, CREATE_NEW_CONSOLE, nil, nil, StartupInfo,
                   ProcessInformation) then
  begin
    hProcess := ProcessInformation.hProcess;
    StartNotifyThread;
  end
  else
  begin
    Result := false;
  end;
end; //StartProcess

Далее NotifyThread:
Код:
procedure NotifyThread;
begin
  Terminated := false;
  WaitForSingleObject(hProcess, INFINITE);
  Writeln('Process stoped.');
  Terminated := true;
  CloseHandle(hThread);
end; //NotifyThread

procedure StartNotifyThread;
var
  ThreadId: Cardinal;
begin
  hThread := CreateThread(nil, 0, @NotifyThread, nil, 0, ThreadId);
end; //StartNotifyThread

procedure StopThread;
begin
  TerminateProcess(hProcess, 255);
  WaitForSingleObject(hProcess, INFINITE);
  CloseHandle(hProcess);
  CloseHandle(hPipeInputWrite);
  CloseHandle(hPipeInputRead);
  CloseHandle(hPipeOutputWrite);
  CloseHandle(hPipeOutputRead);
end; //StopThread

Можно добавить функцию:
Код:
function IsPipeOpen(hPipe: THandle): Boolean;
begin
  Result := (GetFileType(hPipe) = FILE_TYPE_PIPE);
end; //IsPipeOpen

Читаем/пишем в Pipe:
Код:
function GetPipeInfo: string;
var
  BytesCount: Cardinal;
  Buffer: array [0..str_len] of Char;
begin
  Result := '';
  if IsPipeOpen(hPipeOutputRead) then
  begin
    if ReadFile(hPipeOutputRead, Buffer, SizeOf(Buffer), BytesCount, nil) then
    begin
      if BytesCount > 0 then
      begin
        OemToAnsiBuff(Buffer, Buffer, BytesCount);
        Result := Copy(Buffer, 1, BytesCount);
      end;
    end;
  end;
end; //GetPipeInfo

procedure SetPipeInfo(s: string);
const
  br = #13#10;
var
  BytesCount: Cardinal;
  Buffer: array [0..str_len] of Char;
begin
  if Length(s) + 2 < str_len then
  begin
    StrPCopy(Buffer, s + br);
    if IsPipeOpen(hPipeInputWrite) then
    begin
      WriteFile(hPipeInputWrite, Buffer, Length(Buffer), BytesCount, nil);
    end;
  end;
end; //SetPipeInfo

Проверяется так:
Код:
procedure ReadThreadProc;
var
  s: string;
begin
  while not Terminated do
  begin
    s := GetPipeInfo;
    if s <> '' then
    begin
      WritelnRus(s);
      //FormMain.MemoConsole.Text := FormMain.MemoConsole.Text + s;
    end;
    Sleep(100);
  end;
end; //ReadThreadProc

procedure StartPipeRead;
var
  ThreadId: Cardinal;
begin
  CreateThread(nil, 0, @ReadThreadProc, nil, 0, ThreadId);
end; //StartPipeRead

//---
//---

var
  s: string;
begin
  if StartProcess('start.py') then
  begin
    StartPipeRead;
  end;

  //SetPipeInfo('html_code');
 
  while not Terminated do
  begin
    Readln(s);
    if s <> '' then
    begin
      if s = '222' then StopThread;
      SetPipeInfo(s);
    end;
    Sleep(100);
  end;

  Readln;
end.
 
Последнее редактирование:
Код start.py
Python:
# start.py
print("test str")
run = True
while run:
    # Получение данных от main.py
    data = input('start.py -> Enter data: ')

    # Обработка данных и генерация ответа
    response = f"start.py -> Hi, you enter: {data}"

    if data == "111":
        run = False
        print("Exit")

    else:
        # Передача ответа обратно
        print(response)
 
Последнее редактирование:
А ты когда учился писать код и программирование в целом, у тебя не было ошибок? Если ты вообще изучал программирование. Зачем человеку твоя скудная ненужная информацию.
Ошибки бывают у всех, для этого и придумали отладчики (название так и говорит Debugger).
 
Эта реализация мне нужна чтобы запускать _из delphi_ скрипты на python.

Короче, я понел в чем секрет полишинеля. Теперь работает без External exception.

.Сначала создаем процесс:
Код:
function StartProcess(current_file: string): bool;
var
  s: string;
  StartupInfo: TStartupInfo;
  ProcessInformation: TProcessInformation;
  SecurityAttributes: TSecurityAttributes;
begin
  Result := true;

  Writeln('Process started.');

  ZeroMemory(@StartupInfo, SizeOf(TStartupInfo));
  ZeroMemory(@ProcessInformation, SizeOf(TProcessInformation));

  ZeroMemory(@SecurityAttributes, SizeOf(TSecurityAttributes));
 
  SecurityAttributes.nLength := SizeOf(TSecurityAttributes);
  SecurityAttributes.lpSecurityDescriptor := nil;
  SecurityAttributes.bInheritHandle := True;

  CreatePipe(hPipeInputRead, hPipeInputWrite, @SecurityAttributes, 0);
  CreatePipe(hPipeOutputRead, hPipeOutputWrite, @SecurityAttributes, 0);

  StartupInfo.cb := SizeOf(TStartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.hStdInput := hPipeInputRead;
  StartupInfo.hStdOutput := hPipeOutputWrite;
  StartupInfo.hStdError := hPipeOutputWrite;

  s := format('python "%s"', [current_file]);
 
  if CreateProcess(nil, PChar(s), nil, nil,
                   true, CREATE_NEW_CONSOLE, nil, nil, StartupInfo,
                   ProcessInformation) then
  begin
    hProcess := ProcessInformation.hProcess;
    StartNotifyThread;
  end
  else
  begin
    Result := false;
  end;
end; //StartProcess

Далее NotifyThread:
Код:
procedure NotifyThread;
begin
  Terminated := false;
  WaitForSingleObject(hProcess, INFINITE);
  Writeln('Process stoped.');
  Terminated := true;
  CloseHandle(hThread);
end; //NotifyThread

procedure StartNotifyThread;
var
  ThreadId: Cardinal;
begin
  hThread := CreateThread(nil, 0, @NotifyThread, nil, 0, ThreadId);
end; //StartNotifyThread

procedure StopThread;
begin
  TerminateProcess(hProcess, 255);
  WaitForSingleObject(hProcess, INFINITE);
  CloseHandle(hProcess);
  CloseHandle(hPipeInputWrite);
  CloseHandle(hPipeInputRead);
  CloseHandle(hPipeOutputWrite);
  CloseHandle(hPipeOutputRead);
end; //StopThread

Можно добавить функцию:
Код:
function IsPipeOpen(hPipe: THandle): Boolean;
begin
  Result := (GetFileType(hPipe) = FILE_TYPE_PIPE);
end; //IsPipeOpen

Читаем/пишем в Pipe:
Код:
function GetPipeInfo: string;
var
  BytesCount: Cardinal;
  Buffer: array [0..str_len] of Char;
begin
  Result := '';
  if IsPipeOpen(hPipeOutputRead) then
  begin
    if ReadFile(hPipeOutputRead, Buffer, SizeOf(Buffer), BytesCount, nil) then
    begin
      if BytesCount > 0 then
      begin
        OemToAnsiBuff(Buffer, Buffer, BytesCount);
        Result := Copy(Buffer, 1, BytesCount);
      end;
    end;
  end;
end; //GetPipeInfo

procedure SetPipeInfo(s: string);
const
  br = #13#10;
var
  BytesCount: Cardinal;
  Buffer: array [0..str_len] of Char;
begin
  if Length(s) + 2 < str_len then
  begin
    StrPCopy(Buffer, s + br);
    if IsPipeOpen(hPipeInputWrite) then
    begin
      WriteFile(hPipeInputWrite, Buffer, Length(Buffer), BytesCount, nil);
    end;
  end;
end; //SetPipeInfo

Проверяется так:
Код:
procedure ReadThreadProc;
var
  s: string;
begin
  while not Terminated do
  begin
    s := GetPipeInfo;
    if s <> '' then
    begin
      WritelnRus(s);
      //FormMain.MemoConsole.Text := FormMain.MemoConsole.Text + s;
    end;
    Sleep(100);
  end;
end; //ReadThreadProc

procedure StartPipeRead;
var
  ThreadId: Cardinal;
begin
  CreateThread(nil, 0, @ReadThreadProc, nil, 0, ThreadId);
end; //StartPipeRead

//---
//---

var
  s: string;
begin
  if StartProcess('start.py') then
  begin
    StartPipeRead;
  end;

  //SetPipeInfo('html_code');
 
  while not Terminated do
  begin
    Readln(s);
    if s <> '' then
    begin
      if s = '222' then StopThread;
      SetPipeInfo(s);
    end;
    Sleep(100);
  end;

  Readln;
end.
бляздец, писать на дельфи в 2024...
 
Ошибки бывают у всех, для этого и придумали отладчики (название так и говорит Debugger).
Ошибки бывают у всех, и не все сразу знают как их решать, дебагер новичку еще понять надо(НУЖНО)
 
бляздец, писать на дельфи в 2024...
На чем хочу, на том пишу братишка. Тебя это еб#ть не должно.
 
На чем хочу, на том пишу братишка. Тебя это еб#ть не должно.
Мне когда за си предъявляют - также отвечаю :cool:
 
На чем хочу, на том пишу братишка. Тебя это еб#ть не должно.
Если не разберешь и тут никто не поможет в жабу напиши мне я тебе помогу БЕСПЛАТНО, уже делал такое давно на дельфе.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх