环境搭建

使用windows下面的ida pro 6.6调试Linux下面的程序需要使用ida的远程调试功能。
首先将ida文件夹中的dbgsrv/linux_serverx64文件放入需要调试程序的同级文件夹中。再使用chmod a+x linux_serverx64 改变该文件的权限。

运行linux_serverx64


打开IDA,选择Debuger->Run->Remote Linux Debugger

点击ok就可以进行远程调试了。

反汇编分析

首先我们需要找到main函数(前面的是数据初始化过程,不是写的函数的部分)

然后进入的就是client程序反编译出来的汇编代码

.text:00000000004008C6                 push    rbp
.text:00000000004008C7                 mov     rbp, rsp
.text:00000000004008CA                 sub     rsp, 840h  //提升堆栈
.text:00000000004008D1                 mov     rax, fs:28h
.text:00000000004008DA                 mov     [rbp+var_8], rax
.text:00000000004008DE                 xor     eax, eax
.text:00000000004008E0                 mov     rax, 2E302E302E373231h
.text:00000000004008EA                 mov     [rbp+var_820], rax   //[rbp+var_820]为2E302E302E373231h
.text:00000000004008F1                 mov     [rbp+var_818], 31h   //[rbp+var_818]即为31h
.text:00000000004008FA                 mov     edx, 0   //0
.text:00000000004008FF                 mov     esi, 1  //SOCK_STREAM
.text:0000000000400904                 mov     edi, 2  //AF_INET
.text:0000000000400909                 call    sub_4007B0  //调用socket(AF_INET,SOCK_STREAM,0)函数
.text:000000000040090E                 mov     [rbp+var_838], eax   //局部变量[rbp+var_838]就是sockfd
.text:0000000000400914                 lea     rax, [rbp+var_830]
.text:000000000040091B                 mov     edx, 10h      //sizeof(struct sockaddr_in)
.text:0000000000400920                 mov     esi, 0        //0
.text:0000000000400925                 mov     rdi, rax    //rax = [rbp+var_830] 即一个局部变量 struct sockaddr_in servaddr
.text:0000000000400928                 call    sub_400740  //调用memset(&servaddr,0,sizeof(servaddr))函数
.text:000000000040092D                 mov     [rbp+var_830], 2
.text:0000000000400936                 mov     edi, 1F40h   //0x1f40 = 8000 可见端口为8000
.text:000000000040093B                 call    sub_400710   //调用htons
.text:0000000000400940                 mov     [rbp+var_82E], ax  //将转换后的端口号保存到[rbp+var_82E]
.text:0000000000400947                 lea     rax, [rbp+var_830]  //rax = [rbp+var_830] 即一个局部变量 struct sockaddr_in servaddr
.text:000000000040094E                 lea     rdx, [rax+4]
.text:0000000000400952                 lea     rax, [rbp+var_820]  //[rbp+var_820]为2E302E302E373231h
.text:0000000000400959                 mov     rsi, rax      //rsi为[rbp+var_820]为2E302E302E373231h
.text:000000000040095C                 mov     edi, 2     //AF_INET
.text:0000000000400961                 call    sub_400780    //调用inet_pton
.text:0000000000400966                 lea     rcx, [rbp+var_830]
.text:000000000040096D                 mov     eax, [rbp+var_838]    //局部变量[rbp+var_838]就是sockfd
.text:0000000000400973                 mov     edx, 10h        //第三个参数大小
.text:0000000000400978                 mov     rsi, rcx   //第二个参数
.text:000000000040097B                 mov     edi, eax   //第一个参数
.text:000000000040097D                 call    sub_4007A0   //调用connect函数
.text:0000000000400982                 mov     edi, offset aSendMsgToServe ; "send msg to server: "
.text:0000000000400987                 call    sub_4006F0   //调用 printf函数
.text:000000000040098C                 mov     rdx, cs:stdin@@GLIBC_2_2_5  //fget()的第三个参数stdin
.text:0000000000400993                 lea     rax, [rbp+var_810]   
.text:000000000040099A                 mov     esi, 400h  //字符串长度
.text:000000000040099F                 mov     rdi, rax
.text:00000000004009A2                 call    sub_400770   //调用 fgets()函数
.text:00000000004009A7                 lea     rax, [rbp+var_810]
.text:00000000004009AE                 mov     rdi, rax  //将内容设为参数给strlen()
.text:00000000004009B1                 call    sub_400700   //调用 strlen函数
.text:00000000004009B6                 mov     rdx, rax    //发送的信息的长度
.text:00000000004009B9                 lea     rsi, [rbp+var_810]   //发送的信息
.text:00000000004009C0                 mov     eax, [rbp+var_838]   //sockfd
.text:00000000004009C6                 mov     ecx, 0    
.text:00000000004009CB                 mov     edi, eax
.text:00000000004009CD                 call    sub_400720   //调用send()函数
.text:00000000004009D2                 lea     rsi, [rbp+var_410]
.text:00000000004009D9                 mov     eax, [rbp+var_838]   //将连接套接字赋给eax
.text:00000000004009DF                 mov     ecx, 0    //recv 最后一个参数
.text:00000000004009E4                 mov     edx, 400h    //接受大小
.text:00000000004009E9                 mov     edi, eax   //socket连接套接字
.text:00000000004009EB                 call    sub_4006E0   //调用recv函数
.text:00000000004009F0                 mov     [rbp+var_834], eax  //将recv接收到的内容保存给[rbp+var_834]
.text:00000000004009F6                 mov     eax, [rbp+var_834]
.text:00000000004009FC                 cdqe              //转换DWORD(eax)成QWORD(rax)
.text:00000000004009FE                 mov     [rbp+rax+var_410], 0
.text:0000000000400A06                 lea     rax, [rbp+var_410]   //此时的rax即为recv()函数接收到的东西
.text:0000000000400A0D                 mov     rsi, rax
.text:0000000000400A10                 mov     edi, offset aReceivedS ; "Received:%s\n" //将这个字符串的地址给edi给后面打印函数传参
.text:0000000000400A15                 mov     eax, 0     
.text:0000000000400A1A                 call    sub_400730  //调用printf()函数
.text:0000000000400A1F                 mov     eax, [rbp+var_838]   //将sockfd赋给eax
.text:0000000000400A25                 mov     edi, eax     //将sockfd赋给edi
.text:0000000000400A27                 call    sub_400750   //调用close(sockfd)
.text:0000000000400A2C                 mov     edi, 0
.text:0000000000400A31                 call    sub_400790   //exit(0)
.text:0000000000400A36                 db      2Eh
.text:0000000000400A36                 nop     word ptr [rax+rax+00000000h]
.text:0000000000400A36 main            endp ; sp-analysis failed

验证猜想--更改发送内容
1、首先定位到buf地址,由上述反汇编分析中可知,eax中的值为buf的地址。即通过fgets获得的输入内容的存储地址。
2、单步调试,再输入内容后,通过ida的hex-view更改具体值

3、继续执行,得到结果:服务器接收到的内容更变为11111而并非输入的123


4、修改接收到的消息

源程序代码分析

#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<errno.h>  
#include<sys/types.h>  
#include<sys/socket.h>  
#include<netinet/in.h>  
#include<unistd.h>  
#include<arpa/inet.h>           //设置头文件
#define MAXLINE 1024         //定义最大发送大小
#define PORT 8000         //定义端口号
int main()  
{  
    int     sockfd, n, rec_len;  
    char    sendline[MAXLINE];  
    char    buf[MAXLINE];  
    struct sockaddr_in    servaddr;  
    char ipstr[] = "127.0.0.1";/ /变量定义
    sockfd = socket(AF_INET, SOCK_STREAM, 0);//调用套接字函数
    memset(&servaddr, 0, sizeof(servaddr));  
    servaddr.sin_family = AF_INET;  
    servaddr.sin_port = htons(PORT);  
    inet_pton(AF_INET, ipstr, &servaddr.sin_addr.s_addr);
    connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));  //连接服务器
    printf("send msg to server: \n");  
    fgets(sendlig, MAXLINE, stdin);  //录入消息
    send(sockfd, sendline, strlen(sendline), 0) ;   //发送消息

    rec_len = recv(sockfd, buf, MAXLINE,0);  //接受消息
    buf[rec_len]= '\0';  
    printf("Received:%s\n",buf);  //打印接收到的消息
    close(sockfd);    //关闭套接字
    exit(0);  
}

程序代码及注释.rar (0.011 MB) 下载附件
点击收藏 | 0 关注 | 2
登录 后跟帖