В предыдущей статье я разобрал простую программу-валидатор паролей go. В этом можно пойти еще больше. Я попробую перевернуть простой сервер golang с помощью IDA.

Сервер

Ниже приведен исходный код сервера.

Реверсивный

Мы ищем функцию net.Listen (), но перед этим я заметил, что компилятор добавил другие функции. Мы игнорируем, поскольку это не нужно для понимания функциональности программы. Компилятор go, кажется, добавляет множество функций для поддержки многих простых функций, которые мы используем на более высоком уровне. Мы также заметим это позже. Заглянув в IDA, мы видим эту функцию net.Listen () со следующим:

net_listen («tcp», 3, »: 8080», 5) // Числа после строки кажутся длиной строки.

Не то, что я изначально написал в коде. IDA не может точно декодировать строку (или я чего-то не понимаю). Возвращаемое значение находится не в rax / eax, а в стеке. Net_listen () вернет два значения: прослушиватель и значение ошибки, здесь rsp + 30h (rsp + 358) сравнивается с 0, который является нашей обработкой ошибок. (как показано на рисунке ниже), мы можем предположить, что оно содержит значение err.

При дизассемблировании отсрочка вызова функции может быть идентифицирована с помощью функции runtime_deferproc (). И здесь кажется, что возвращаемое значение передается в eax. И компилятор добавил сюда собственную обработку ошибок.

Затем мы видим вызов rax. Что это за функция? Я запустил программу в x64dbg, и, похоже, это функциональность слушателя. (Извините за плохое качество изображения)

Он вызывает функцию accept () из исходного кода. Хмммм. Я иду в IDA, чтобы узнать, какое значение было передано в rax (поскольку я нигде не заметил функцию .Accept ()), похоже, значение было из стека (снова).

Тип слушателя находится по смещению rsp + 0x58, а функция accept () - по смещению rsp + 0x58 + 0x18. Теперь, когда соединение установлено, мы использовали bufio.NewReader для чтения. Компилятор, похоже, добавил много важных функций, которые мы не создавали. Среди них был вызов runtime_makeslice (), я думаю, поскольку пользовательский ввод может быть любой длины, используется срез.

После этого мы использовали io.WriteString (), чтобы передать сообщение клиентам. Используя x64dbg, мы видим, что он очень похож на другие вызовы функций go.

Вывод

  • Компилятор go добавляет множество функций, которые необходимы для функций более высокого уровня, которые мы используем.
  • Кажется, что возвращаемое значение может быть как в самом стеке, так и в регистрах. Лучше всего написать небольшую программу с рассматриваемыми функциями, а затем наблюдать.
  • В случае сомнений используйте отладчик