2017-01-22 1 views
-1

私はサーバーバイナリのアセンブリをリバースエンジニアリングしていますが、recv呼び出しに関するいくつかのコードを理解する上で問題があります。recvを使用しているときにバッファがメッセージよりも小さい間にループするのはなぜですか?

私は、アセンブリから次の擬似コードを導出し、whileループ条件は私を混乱させる:

 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内の部分的なリストとしてではなく、あなたの質問にプレーンテキストとして完全な逆アセンブリをコピーすることもできます。今私はあなたの擬似コードが間違っていると仮定することができます。 esp + = 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

あなたがプログラム内の2つの異なる値に名前buffer_lenを適用しているように見えます。引数に渡されたbuffer_lenと、recvのパラメータである第2のbuffer_lenがあります。これらは実際には2つの異なるものです。最初のものはEBXに保存され、決して変更されません。 2番目はrecvへのコールの前に一時的にEDXに格納されます。

機能のより直訳は次のようになります。

これなる簡易
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

有益な答えをありがとう。なぜループはこの状態で書かれますか?バッファの全長が満たされていない場合、なぜrecvはコンテンツ全体を返すのでしょうか? – ideanl

+1

@ideanl後でさらにデータを送信できるためです。これがTCPストリームを読み取っている場合、 'recv'は' packets 'を読み取らず、単にストリームからバイトを読み込みます。コードは、1つの完全なアプリケーションレベルのパケットが受信されるまで待つか、チャンク内のデータを処理できるように任意のサイズのバッファを満たすだけです。 –

関連する問題