Нарушение доступа с помощью P / Invoke SendMessage и Message.GetLParam - PullRequest
0 голосов
/ 14 декабря 2011

Я получаю прерывистую ошибку при вызове Message.GetLParam, получая сообщения, отправленные между процессами. У меня есть два процесса, оба написаны на C # (.Net 3.5). Я использую функцию Win32 SendMessage () для отправки данных от одного процесса (источник) к другому (цель). Главное окно целевого процесса (это приложение Windows Forms) переопределяет функцию WndProc () для получения сообщений. Исходный процесс находит другой с помощью функции Process.GetProcessesByName (), а затем с помощью Process.MainWindowHandle, чтобы получить дескриптор окна, в который я хочу отправить сообщение. Код исходного кода выглядит так:

Process[] procs = Process.GetProcessesByName("MyTargetProcess");
if (procs != null 
    && procs.Length > 0)
{
    IntPtr win = procs[0].MainWindowHandle;
    var someData = new Win32.COPYDATASTRUCT   // This is a struct that I defined
    {
    // Initialize fields of the struct
    };
    Win32.SendMessage(win,
        Win32.MyMsgCode,    // my custom message
        IntPtr.Zero,    // wParam = 0
        ref someData);
}

Код целевого процесса выглядит следующим образом:

protected override void WndProc(ref System.Windows.Forms.Message m)
{
    if (m.Msg == Win32.MyMsgCode)
    {
    Win32.COPYDATASTRUCT ds;
        try
        {
            ds = (Win32.COPYDATASTRUCT)m.GetLParam(typeof(Win32.COPYDATASTRUCT));
        }
        catch (Exception ex)
        {
            log.ErrorFormat("Got exception in WndProc", ex);
        }
        // Do something with the message
        ....
}

Win32 - статический класс, который я определил, который получает все мои определения P / Invoke. Я не понимаю, почему я ловлю AccessViolationException в WndProc. У кого-нибудь есть идея, почему? и почему это происходит только иногда?

Спасибо за внимание!

-------------------------------- РЕДАКТИРОВАТЬ -------------- ---------------------------- Еще одна вещь, которая ставит меня в тупик: COPYDATASTRUCT объявлен как

public static readonly int WM_COPYDATA = 0x004a;
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
    // Specifies data to be passed to the receiving application.
    public string dwData;
    // Specifies the size, in bytes, of the data pointed to by the lpData member. 
    public int cbData;
    // Pointer to data to be passed to the receiving application. This member can be NULL.                 
    public string lpData;
}

Инициализируется так:

string payload = " some data ";
var someData = new Win32.COPYDATASTRUCT   // This is a struct that I defined
{
    dwData = "bogusData",
    cbData = sizeof(char) * payload.Length,
    lpData = payload
};

А в целевом коде я всегда получаю dwData = null.

----------------------- 2-е редактирование ---------------------- ---------------- Я только что попытался с добавлением нулевого терминатора, и я все еще получаю ошибку. Если я изменю код маршаллинга, чтобы сделать свой собственный маршаллинг, как в

IntPtr pcds = Marshal.AllocHGlobal(Marshal.SizeOf(someData));
Marshal.StructureToPtr(someData, pcds, true);
Win32.SendMessage(win, (uint)Win32.WM_COPYDATA, IntPtr.Zero, pcds);

Тогда ошибка происходит ВСЕ ВРЕМЯ! Однако, если я повторю вызов GetLParam () в блоке catch, он будет успешен почти все время, со второй попытки.

1 Ответ

0 голосов
/ 14 декабря 2011

Меня бросает в глаза то, что cbData установлен неправильно.Вы должны учитывать нулевой терминатор в конце строки.

 cbData = sizeof(char) * (payload.Length+1)

Это, безусловно, объясняет ошибку.Когда вы отправляете сообщение, маршаллинг WM_COPYDATA не будет копировать нулевой терминатор, и получатель затем будет читать после конца буфера неинициализированные значения.

Мне также интересно узнать о sizeof(char).Вы называете Unicode-версию SendMessage?Если нет, то я ожидаю увидеть нарушения доступа в отправляющем коде.

Вам также следует опасаться, что приложение получателя само откроется для переполнения буфера.Поскольку он игнорирует значение cbData и обрабатывает поле lpData как указатель с нулевым символом в конце, злоумышленник может заставить ваше приложение выполнить произвольный код.Чтобы защититься от этого, вы должны скопировать данные, cbData байт, в байтовый массив, а затем преобразовать в строку.

Другая проблема заключается в том, что вам нужно объявить dwData как UIntPtr.Как вы определили структуру, код получателя обрабатывает dwData как указатель на строку, которая провоцирует AV, потому что вы пересекли границы процесса.

Я бы также указал, что cbData не подписанои должно быть uint, но это доброкачественная ошибка здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...