
正文一、静态分析二、计算有效 Flag三、验证计算结果正文kali攻击机地址192.168.1.47靶场地址192.168.1.48一、静态分析进到程序后shiftF12编译成字符串然后CtrlF搜索flag看到提示this is the right flag!双击进去CTRLX查看谁调用了这个字段点击OK进入跳转。跳转过后直接F5反编译一下是一段伪代码代码很抽象对吧逐行去理解// 快速调用约定main函数参数参数个数、命令行参数、环境变量int__fastcallmain(intargc,constchar**argv,constchar**envp)64 位 Linux ELF 程序编译器默认对main使用__fastcall调用约定因为这是反编译的代码所以没有写成int main(int argc, char* argv[], char* envp[]);然后是变量参数intstat_loc;// [rsp4h] [rbp-3Ch] BYREF 存放子进程退出状态码inti;// [rsp8h] [rbp-38h] 循环遍历下标变量__pid_t pid;// [rspCh] [rbp-34h] 存放fork创建的进程IDchars2[24];// [rsp10h] [rbp-30h] BYREF 接收用户输入的字符数组大小24字节unsigned__int64 v8;// [rsp28h] [rbp-18h] 栈溢出保护校验值(Canary)// 读取fs段寄存器偏移0x28位置的栈保护金丝雀防止栈溢出v8__readfsqword(0x28u);我们只用理解这个变量的类型 给谁赋值 在哪使用。然后是函数部分有意思的一个地方waitpid(pid,stat_loc,0);第 1 个实参pid就是前面fork得到的子进程 ID→ 锁定等待pid 这个子进程第 2 个实参stat_loc取 stat_loc 变量地址→ 函数内部会把子进程退出状态数据回写进 stat_loc第 3 个实参0固定代表阻塞模式阻塞意思父进程停在这里不动啥也不干一直等到子进程跑完才继续往下执行二、计算有效 Flag到这里我们就可以重点分析子进程的运行逻辑// 子进程执行代码// 循环遍历全局变量flag字符串每一个字符for(i0;istrlen(flag);i){// ASCII 105 i 114 rif(flag[i]105||flag[i]114)// ASCII 49 字符 1flag[i]49;// 把i和r全部替换成数字1}说明在flag字符串的内容里把i和r换成数字1仔细看原来的伪代码注释处已经告诉你flag的字符内容。所以意思就是说字符{hacking_for_fun}ASCII7b6861636b696e675f666f725f66756e7d原始: {h a c k i n g _ f o r _ f u n} ↓ ↓ 修改后: {h a c k 1 n g _ f o 1 _ f u n}三、验证计算结果Tab键分析注释代码看看flag的存放位置发现这个flag的存放地址为0x601080那我们就跟踪一下子进程执行完后这个flag的值的变化gdb ./reverse_2# 2. 设置跟踪子进程(gdb)setfollow-fork-mode child# 3. 设置不分离父进程可选(gdb)setdetach-on-fork off# 4.在printf处打断点(gdb)bprintf# 5.运行程序(gdb)run# 6.查看flag值的变化(gdb)x/s 0x601080再把整个伪代码吃透就能理解了。// 快速调用约定main函数参数参数个数、命令行参数、环境变量int__fastcallmain(intargc,constchar**argv,constchar**envp){intstat_loc;// [rsp4h] [rbp-3Ch] BYREF 存放子进程退出状态码inti;// [rsp8h] [rbp-38h] 循环遍历下标变量__pid_t pid;// [rspCh] [rbp-34h] 存放fork创建的进程IDchars2[24];// [rsp10h] [rbp-30h] BYREF 接收用户输入的字符数组大小24字节unsigned__int64 v8;// [rsp28h] [rbp-18h] 栈溢出保护校验值(Canary)// 读取fs段寄存器偏移0x28位置的栈保护金丝雀防止栈溢出v8__readfsqword(0x28u);// fork()系统调用创建一个新子进程// 父进程返回子进程PID子进程返回0创建失败返回-1pidfork();// 判断当前是父进程还是子进程if(pid){// 父进程执行代码// 阻塞等待pid对应的子进程运行结束把子进程退出状态存入stat_locwaitpid(pid,stat_loc,0);}else{// 子进程执行代码// 循环遍历全局变量flag字符串每一个字符for(i0;istrlen(flag);i){// ASCII 105 i 114 rif(flag[i]105||flag[i]114)// ASCII 49 字符 1flag[i]49;// 把i和r全部替换成数字1}}// 控制台打印提示语printf(input the flag:);// 读取用户输入最多读取20个字符存入s2数组__isoc99_scanf(%20s,s2);// 字符串比对用户输入s2 和 修改后的全局flag是否完全一致if(!strcmp(flag,s2))// 相等输出正确returnputs(this is the right flag!);else// 不相等输出错误returnputs(wrong flag!);}