Работа с NetBIOS

Фленов Михаил

Xakep, номер #050, стр. 080-081

smiandr@mail.ru

http://www.cydsoft.com/vr-online/

Сегодня я решил рассказать тебе о работе протокола NetBIOS и о том, как его кодить в своих программах. Он достаточно прост, потому что API протокола состоит только из одной функции Netbios. Несмотря на то, что функция одна, она умеет больше, чем любая другая функция из других сетевых библиотек. Поэтому я не смогу ее описать всю, но небольшие начальные сведения постараюсь дать.

В Windows за работу NetBIOS отвечает библиотека netapi32.dll. Это значит, что поклонникам языка С++ нужны будут заголовочные файлы и файл библиотеки netapi32.lib. Нам, дельфинам, немного проще - достаточно только заголовочного файла nb.pas. Его ты найдешь на диске к этому номеру или вместе с исходником на моем сайте.

Как я уже сказал, вся библиотека NetBIOS крутится вокруг одноименной функции, и ее объявление выглядит таким образом:

function NetbiosCmd(var NCB: TNCB): Word;

Как видишь, у нее только один параметр - структура NCB. Это довольно сложная структура, в которой и заключается вся работа. С ее помощью ты будешь говорить библиотеке, что от нее требуется, а также принимать и получать любые данные.

Всемогущий NCB

Теперь перейдем к более конкретному изучению структуры NCB. Ее описание для Windows выглядит так:

  TNCB = packed record
    Command: byte;
    RetCode: byte;
    LSN: byte;
    Num: byte;
    Buf: ^byte;
    Length: word;
    CallName: TNBName;
    Name: TNBName;
    RTO: byte;
    STO: byte;
    PostPrc: TNCBPostProc;
    Lana_Num: byte;
    Cmd_Cplt: byte;
    Reserved: array[0..9] of byte;
    Event: THandle;
  end;

  1. Первый параметр (command) указывает на команду, которую необходимо выполнить. Я не смогу их описать все, но могу посоветовать заглянуть в заголовочный файл и поискать константы, начинающиеся с NCB_. Все это (кроме NCB_ASYNC) и есть имена констант, указывающих на определенные команды. Константа NCB_ASYNC имеет особое значение. Если ты просто укажешь необходимую команду, то она будет выполнена синхронно. Но если ее поразрядно логически сложить (для этого вместо знака + указывают and, хотя и простое сложение тоже сработает) с константой NCB_ASYNC, то команда будет уже выполнена асинхронно.
  2. Второй параметр (RetCode) содержит код результата выполнения команды. Если ты выполняешь ее асинхронно, то NetBIOS не может сразу вернуть результат. Поэтому в этом случае сюда будет помещено значение $ff или константа NRC_PENDING, означающая, что асинхронная команда еще не выполнена. Константы возвращаемых значений можно найти в заголовочном файле. Начинаются они с NRC_.
  3. Параметр LSN - номер локального сеанса, который ты можешь получить после выполнения команд NCB_CALL (открыть сессию) и NCB_LISTEN (ждать вызова).
  4. Num - номер сетевого имени. Такие номера получаются после вызова команд NCB_ADDNAME (добавить уникальное имя в локальную таблицу) и NCB_ADDGRPNAME (добавить имя группы в локальную таблицу).
  5. Следующий параметр (Buf) - это буфер, в котором нужно размещать данные, которые необходимо отправить в сеть. Здесь также можно получить данные, принятые из сети.
  6. Length - длина буфера. По этому числу библиотека сможет узнать, сколько данных ты хочешь отправить в сеть или получить.
  7. Параметр CallName - это имя удаленного приложения.
  8. Противоположность предыдущему Name - имя твоей программы.
  9. Далее идет RTO - время ожидания (time-out) при получении данных. Учти, что ты указываешь число единиц времени, а одна единица равна 500 миллисекундам. Одна секунда равна 1000 миллисекундам, а значит, если указать число 2, то мы попросим ожидать приема ровно 1 секунду.
  10. Противоположностью предыдущему является STO - время ожидания отправки данных по сети. Также указывается в единицах, где одна единица равна 500 миллисекундам.
  11. PostPrc указывает на процедуру, которую необходимо выполнить после выполнения команды в асинхронном режиме. Такая процедура должна иметь вид: TNCBPostProc = procedure(P: PNCB); Это значит, что она обязана иметь один и только один параметр в виде переменной типа PNCB, т.е. указатель на структуру TNCB. Если ты работаешь в доисторическом Windows 3.11 (мои соболезнования), то этот параметр будет состоять из пары параметров Post_Offs и Post_Seg (указатель на сегмент и смещение).
  12. Lana_Num - номер адаптера, с которым необходимо работать.
  13. Cmd_Cplt - это код выполнения команды. Здесь также при асинхронной работе будет стоять значение $ff или константа NRC_PENDING.
  14. Reserved - зарезервированный параметр. Должен равняться нулю.
  15. Event - удобная фишка Win32 - событие. Его удобно использовать при работе в асинхронном режиме, когда необходимо узнать моменты окончания выполнения асинхронной операции.

Как работает пример

Я не буду описывать весь пример, потому что для него уже не остается места, но дам несколько замечаний. Прежде чем использовать протокол NetBIOS, я вызываю свою функцию NbLanaEnum, в которой происходит перечисление всех доступных в компьютере сетевых устройств. Для этого используется NetBIOS команда NCB_ENUM.

После этого запускается цикл для всех найденных устройств (LANA). Внутри цикла я, по идее, должен просто определить MAC-адрес устройства - но не тут-то было. В NetBIOS, прежде чем использовать любой LANA, его надо обнулить. Для этого я вызываю свою процедуру NbReset, в которой выполняю NetBIOS команду NCB_RESET. Не пренебрегай обнулением, даже если уверен, что программа сработает без этой команды. Никогда нельзя быть уверенным на 100%.

А теперь, после перечисления и обнуления, я смело могу вызывать свою функцию NbGetMacAddr, которая как раз и определит соответствующий устройству МАС-адрес.

Когда будешь разбираться с кодом, то обрати внимание на одну закомментированную строку:

NCB.CallName[0] := Byte('*');

Если в параметре CallName указать звездочку, то ты указываешь локальную машину, и необязательно знать ее NetBIOS. Если нужна удаленная тачка, то делай именно так, как в примере.

Шкодинг

В этой статье я рассказал теорию, которую нельзя объяснить с помощью только примера. Без понимания всего описанного невозможно изучать NetBIOS. Но небольшой пример у меня для тебя все же есть. Я написал небольшую программку, которая по NetBIOS имени компьютера определяет его MAC-адрес. Этот пример находится на диске вместе с необходимым заголовочным файлом для Delphi и на моем сайте в разделе Хакер-Исходники.

<Ты спрашивал???> Как удалять каталоги с поддиректориями. Какой командой?

H: Следующая функция универсальна для удаления, переименования, копирования файлов (не забудь в раздел uses добавить модуль ShellAPI):

function TForm1.DoSHFileOp(Handle: THandle; OpMode: UInt; Src, Dest: string; DelRicleBin: Boolean): Boolean;
var
  Ret: integer;
  ipFileOp: TSHFileOpStruct;
begin
  Screen.Cursor:=crAppStart;
  FillChar(ipFileOp, SizeOf(ipFileOp), 0);
  with ipFileOp do
  begin
    wnd := Handle;
    wFunc := OpMode;
    pFrom := pChar(Src);
    pTo := pChar(Dest);
    if DelRicleBin then
    fFlags := FOF_ALLOWUNDO
    else
    fFlags := FOF_NOCONFIRMMKDIR;
    fAnyOperationsAborted := False;
    hNameMappings := nil;
    lpszProgressTitle := '';
  end;
  try
    Ret := SHFileOperation(ipFileOp);
    except
    Ret := 1;
  end;
  result := (Ret = 0);
  Screen.Cursor:=crDefault;
end;
//Следующая процедура - пример удаления файлов и каталогов
procedure TForm1.Delete;
const
  FileOpMode: array[0..3] of UInt =(FO_COPY, FO_DELETE, FO_MOVE, FO_RENAME);
var
  i: integer;
  DelFName: string;
  DelReg:Boolean;
begin
  DelFName:='c:Diame'+#0;
  DoSHFileOp(Handle, FO_DELETE, DelFName, DelFName, true);
end;

Содержание
ttfb: 3.7810802459717 ms