2017-01-22 5 views
-1

Я реконструирую некоторую сборку для бинарного сервера, и у меня возникли проблемы с пониманием кода вокруг вызова recv.Почему цикл, пока буфер меньше, чем сообщение при использовании recv?

Я вывел следующий псевдокод из сборки, и состояние в то время как петля меня смущает:

 func_804a890(int socket, void *buffer_start, size_t buffer_len, int num_open_descriptors) { 
    int a, b, c; 

    if (buffer_start == 0 || buffer_len == 0) 
    //goto 0x804a8e8 

    size_t msg_len = 0; 
    void* buffer; 
    ssize_t packet_len = 0; 

    do { 
    buffer_len -= packet_len; 
    buffer = buffer_start + msg_len; 
    packet_len = recv(socket, buffer, buffer_len, 0); 
    if (packet_len == -1) { 
     return -1; 
    } 
    else if (packet_len == 0) { 
     //goto 0x804a8f8 
    } 
    else { 
     //goto 0x804a8bc 
    } 

    msg_len += packet_len; 

    } while(buffer_len > msg_len); 
} 

Почему я петля, если буфер больше, чем сообщение от клиента? Далее идет соответствующая функция сборки в случае, если я не интерпретировать одну из переменных правильно в моем псевдо-код:

.text:0804a890 55        push ebp 
.text:0804a891 57        push edi 
.text:0804a892 56        push esi 
.text:0804a893 53        push ebx 
.text:0804a894 83 ec 0c       sub esp,0xc 
.text:0804a897 8b 74 24 24      mov esi,DWORD PTR [esp+0x24] 
.text:0804a89b 8b 7c 24 20      mov edi,DWORD PTR [esp+0x20] 
.text:0804a89f 8b 5c 24 28      mov ebx,DWORD PTR [esp+0x28] 
.text:0804a8a3 85 f6       test esi,esi 
.text:0804a8a5 74 41       je  0x0804a8e8 
.text:0804a8a7 85 db       test ebx,ebx 
.text:0804a8a9 74 3d       je  0x0804a8e8 
.text:0804a8ab 31 c0       xor eax,eax 
.text:0804a8ad 31 ed       xor ebp,ebp 
.text:0804a8af eb 13       jmp 0x0804a8c4 
.text:0804a8b1 8d b4 26 00 00 00 00    lea esi,[esi+eiz*1+0x0] 
.text:0804a8b8 85 c0       test eax,eax 
.text:0804a8ba 74 3c       je  0x0804a8f8 
.text:0804a8bc 01 c5       add ebp,eax 
.text:0804a8be 39 eb       cmp ebx,ebp 
.text:0804a8c0 89 e8       mov eax,ebp 
.text:0804a8c2 76 24       jbe 0x0804a8e8 
.text:0804a8c4 89 da       mov edx,ebx 
.text:0804a8c6 6a 00       push 0x0 
.text:0804a8c8 29 c2       sub edx,eax 
.text:0804a8ca 01 f0       add eax,esi 
.text:0804a8cc 52        push edx 
.text:0804a8cd 50        push eax 
.text:0804a8ce 57        push edi 
.text:0804a8cf e8 3c ec ff ff     call 0x08049510 
.text:0804a8d4 83 c4 10       add esp,0x10 
.text:0804a8d7 83 f8 ff       cmp eax,0xffffffff 
.text:0804a8da 75 dc       jne 0x0804a8b8 
.text:0804a8dc 83 c4 0c       add esp,0xc 
.text:0804a8df 5b        pop ebx 
.text:0804a8e0 5e        pop esi 
.text:0804a8e1 5f        pop edi 
.text:0804a8e2 5d        pop ebp 
.text:0804a8e3 c3        ret  
+0

Попробуйте запустить декомпилятор снеговика derevenets.com в вашей функции, чтобы получить исправленный псевдокод. Вы также можете скопировать полную разборку в виде обычного текста в свой вопрос, а не как частичный листинг внутри jpg. Теперь я могу предположить, что ваш псевдокод неверен, так как есть 'call ...; ЭСП + = 16; cmp eax и -1; if eax! = -1 ([не было ошибки в recv] (http://man7.org/linux/man-pages/man2/recv.2.html#RETURN_VALUE)) jmp для a8b8. Поэтому у вас, вероятно, неправильный аргумент цикла while; должна быть какая-то дополнительная логика и поток управления внутри цикла. – osgx

+3

Текст, а не текст. – melpomene

+0

Отредактировано сообщение и опубликовано функция как текст. Я не могу опубликовать весь файл, поскольку он очень длинный. – ideanl

ответ

2

Вы кажетесь применили имя buffer_len для двух различных значений в программе. Есть buffer_len, который передается в аргументе, а второй buffer_len - это параметр recv. На самом деле это две разные вещи. Первый хранится в EBX и никогда не изменяется. Второй временно сохраняется в EDX перед вызовом recv.

Более буквальный перевод функции будет:

int 
func_804a890(int arg1, int arg2, int arg3) { 
    int esi = arg2; 
    int edi = arg1; 
    unsigned ebx = arg3; 

    if (esi != 0 && ebx != 0) { 
     int eax = 0; 
     unsigned ebp = 0; 
     while(1) { 
      int edx = ebx; 
      edx -= eax; 
      eax += esi; 
      eax = recv(edi, (void *) eax, edx, 0); 
      if (eax == -1) { 
       return eax; 
      } 
      if (eax == 0) { 
       /* ??? */ 
      } 
      ebp += eax; 
      eax = ebp; 
      if (ebx <= ebp) { 
       break; 
      } 
     } 
    } 
    /* ??? */ 
} 

Упрощенная это становится:

int 
func_804a890(int socket, char *buffer, unsigned len) { 
    if (buffer != 0 && len != 0) { 
     unsigned pos = 0; 
     while(1) { 
      int recv_len = recv(socket, buffer + pos, len - pos, 0); 
      if (recv_len == -1) { 
       return recv_len; 
      } 
      if (recv_len == 0) { 
       /* ??? */ 
      } 
      pos += recv_len; 
      if (len <= pos) { 
       break; 
      } 
     } 
    } 
    /* ??? */ 
} 

Цикл продолжается, пока общее количество полученных (pos) меньше, чем длина буфера передается функции (len).

+0

Спасибо за полезный ответ. Почему цикл должен быть записан с этим условием? Если полная длина буфера не заполнена, зачем возвращать больше содержимого для заполнения всей длины? – ideanl

+1

@ideanl Потому что больше данных можно отправить позже. Если этот поток TCP считывается, то 'recv' не читает« пакеты », он просто считывает байты из потока. Код может быть либо до тех пор, пока не будет получен один полный пакет уровня приложения, либо он может просто заполнить буфер произвольного размера, чтобы он мог обрабатывать данные в кусках. –