复盘网鼎杯Re-Signal Writeup

2023-12-05 19:48

本文主要是介绍复盘网鼎杯Re-Signal Writeup,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Signal

  • 0x0 引言
  • 0x1 查壳
  • 0x2 分析 main
  • 0x3 瞧一瞧 __main()
  • 0x4 内存复制
  • 0x5 分析 vm_operad
  • 0x6 调试计算 V5
  • 0x7 总结

0x0 引言

比赛时没能做出来这道题,当时我使用OD进行动态调试,分析出启动程序时初始化了0x72数组,并且含有一个12分支的switch被嵌套在循环中,最终没能搞定,今天就复盘这道题。

0x1 查壳

在这里插入图片描述
无壳,并且编译时未启用ASLR技术,挺友好哈。

0x2 分析 main

在这里插入图片描述
这次学聪明了,先打开反汇编辅助插件查看伪代码(这对理解汇编逻辑有极大的帮助)。

可以看到在 main 函数中先调用了 __main()
随后复制内存到变量v4,随后v4被传入vm_operad()
容易想到,&unk_403040 是通过 __main() 得到的,随后的vm_operad()则是在计算flag,并在puts()中输出。

0x3 瞧一瞧 __main()

GO TO:0x0040176F
通过OD动态调试,F8步过发现寄存器中没有任何的变化,所以我认为之后的操作与__main()函数是无关的。

0x4 内存复制

在这里插入图片描述
rep movsd 根据百科上的定义,赋值edx次,即0x72次
其中esi指向的地址为0x403040,如下
在这里插入图片描述
再来看反汇编代码。
在这里插入图片描述
内存复制,从0x403040复制到变量v4,大小为0x1C8个字节。

可能存在疑问,在汇编代码中是0x72,为啥反汇编后是0x1C8呢?
在这里插入图片描述
其实很简单,因为数据类型为DWORD占4个字节,这从上文中数据硬编码处可以看出。
0x1C8 = 0x72 * 0x4
还有一个很奇怪的现象,puts中只传入了字符串模板,而没有传入存储flag的地址…

0x5 分析 vm_operad

使用IDA自动反汇编 vm_operad(int *a1, int a2)
int * a1传入的是之前的v4首地址,a2为常数114
经过部分的调整与修改我得到了源代码如下:

#include<iostream>
#include<windows.h>
#include<string>
using namespace std;size_t  read(char *a1)
{size_t result; // eaxprintf("string:");scanf("%s", a1);result = strlen(a1);if ( result != 15 ){puts("WRONG!\n");exit(0);}return result;
}int vm_operad(unsigned int *a1, int a2)
{int result; // eaxchar v3[100]; // [esp+13h] [ebp-E5h]char v4[100]; // [esp+77h] [ebp-81h]char v5; // [esp+DBh] [ebp-1Dh]int v6; // [esp+DCh] [ebp-1Ch]int v7; // [esp+E0h] [ebp-18h]int v8; // [esp+E4h] [ebp-14h]int v9; // [esp+E8h] [ebp-10h]int v10; // [esp+ECh] [ebp-Ch]v10 = 0;v9 = 0;v8 = 0;v7 = 0;v6 = 0;while ( 1 ){result = v10;if ( v10 >= a2 )return result;switch ( a1[v10] ){case 0:case 9:continue;case 1:v4[v7] = v5;++v10;++v7;++v9;break;case 2:v5 = a1[v10 + 1] + v3[v9];v10 += 2;break;case 3:v5 = v3[v9] - LOBYTE(a1[v10 + 1]);v10 += 2;break;case 4:v5 = a1[v10 + 1] ^ v3[v9];v10 += 2;break;case 5:v5 = a1[v10 + 1] * v3[v9];v10 += 2;break;case 6:++v10;break;case 7:if ( v4[v8] != a1[v10 + 1] ){printf("what a shame...");exit(0);}++v8;v10 += 2;break;case 8:v3[v6] = v5;++v10;++v6;break;case 10:read(v3);++v10;break;case 11:v5 = v3[v9] - 1;++v10;break;case 12:v5 = v3[v9] + 1;++v10;break;}}
}int main(){unsigned int a[] ={0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xfffffff1,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};cout << sizeof(a) / sizeof(a[0]);vm_operad(&a,114);return 0;
}

分析到这里有点懵逼,因为不知道啥是我们要的flag,我们只是拿到了源代码,而且这代码这么多的分支,感觉和我当时用OD调试没啥大的区别。
在这里插入图片描述
通过可视化,可以知道,如果想反向求解存在一定的困难,因为swich分支太多啦!

通过已得到的反汇编代码,v3 v4 为长度100的字符数组,由于最后的输出中根本没有flag,所以猜测v3 v4可能就是我们想要的flag。

在这里插入图片描述
在这里插入图片描述
v3 变量在 case8 中被改变,在case10中被输入,输入长度为15
在这里插入图片描述
在这里插入图片描述
v4case 1 中被改变,case7 中将他与a1元素进行比较,a1中的元素是已知的,为了方便,我把a1改名为array
这里我将printf() 和 exit() 注释,并在read()中随机输入15个字符
在这里插入图片描述
在这里插入图片描述
多次执行后发现规律。
在这里插入图片描述
case7 中输出了v4每个元素的验证值 array[v10 + 1] 是常数,这就相当于我们已知了v4数组,而v4是在case 1中赋值为 v5,其中0xffffff不知道为啥显示不全,在OD中他的值为0xfffffff1

 v4 = {0x22,0x3f,0x34,0x32,0x72,0x33,0x18,0xffffffa7,0x31,0xf1,0x28,0xffffff84,0xffffffc1,0x1e,0x7a};

现在就得着重研究V5

0x6 调试计算 V5

#include<iostream>
#include<windows.h>
#include<string>
using namespace std;size_t  read(char *array)
{for(int i=0;i<15;i++){array[i] = rand() * 255;}return 15;size_t result; // eaxprintf("string:");scanf("%s", array);result = strlen(array);if ( result != 15 ){puts("WRONG!\n");exit(0);}return result;
}void displayV9V10(int _case ,int v9,int v10){return;printf("case %d\tv9=%d\tv10=%d\n",_case,v9,v10);
}int vm_operad(unsigned int *array, int a2)
{int result; // eaxchar v3[100]; // [esp+13h] [ebp-E5h]char v4[100]; // [esp+77h] [ebp-81h]char v5; // [esp+DBh] [ebp-1Dh]int v6; // [esp+DCh] [ebp-1Ch]int v7; // [esp+E0h] [ebp-18h]int v8; // [esp+E4h] [ebp-14h]int v9; // [esp+E8h] [ebp-10h]int v10; // [esp+ECh] [ebp-Ch]v10 = 0;v9 = 0;v8 = 0;v7 = 0;v6 = 0;while ( 1 ){result = v10;if ( v10 >= a2 ){// cout << "v3: ";// for(int i = 0; v3[i] != '\0';i++){//     cout << int(v3[i]) << " ";// }// cout << endl;// cout << "v4: ";// for(int i = 0; v4[i] != '\0';i++){//     cout << int(v4[i]) << " ";// }// cout << endl;// cout << int(v5) << " "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" "<<v10<<endl;return result;}switch ( array[v10] ){case 0:case 9:continue;case 1:displayV9V10(1,v9,v10);printf("v4[%d] = v5; \n\n\n",v7);v4[v7] = v5;++v10;++v7;++v9;break;case 2:displayV9V10(2,v9,v10);printf("v5 = array[%d] + v3[%d]; \n",v10 + 1,v9);v5 = array[v10 + 1] + v3[v9];v10 += 2;break;case 3:displayV9V10(3,v9,v10);printf("v5 = v3[%d] - LOBYTE(array[%d]); \n",v9 ,v10 + 1);v5 = v3[v9] - LOBYTE(array[v10 + 1]);v10 += 2;break;case 4:displayV9V10(4,v9,v10);printf("v5 = array[%d] ^ v3[%d]; \n",v10 + 1,v9);v5 = array[v10 + 1] ^ v3[v9];v10 += 2;break;case 5:displayV9V10(5,v9,v10);printf("v5 = array[%d] * v3[%d]; \n",v10 + 1,v9);v5 = array[v10 + 1] * v3[v9];v10 += 2;break;case 6:++v10;break;case 7:// 输出验证信息cout << "case[7] " << "v4:"  << v8  << "\t\t" << int(v4[v8]) << "\t\t" <<  int(array[v10 + 1]) <<endl << dec;if ( v4[v8] != array[v10 + 1] ){// printf("what a shame...");// exit(0);}++v8;v10 += 2;break;case 8:displayV9V10(8,v9,v10);printf("v3[%d] = v5; \n",v6);v3[v6] = v5;++v10;++v6;break;case 10:read(v3);++v10;break;case 11:displayV9V10(11,v9,v10);printf("v5 = v3[%d] - 1; \n",v9);v5 = v3[v9] - 1;++v10;break;case 12:displayV9V10(12,v9,v10);printf("v5 = v3[%d] + 1; \n",v9);v5 = v3[v9] + 1;++v10;break;}}
}int main(){unsigned int a[] ={0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xffffff,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};int test;while(1){unsigned int *b = new unsigned int[114];for(int i = 0; i < 114;i++)b[i] = a[i];vm_operad(b,114);delete [] b;cout <<"input a int to try again:"<<endl;cin >> test;}return 0;
}

打印运算V5casecase 1

由于V4已知,所以可以求出对应的V3,以下为打印获取计算过程

v5 = array[2] ^ v3[0];         
v3[0] = v5; 
v5 = v3[0] - LOBYTE(array[5]); 
v4[0] = v5; v5 = array[8] ^ v3[1];         
v3[1] = v5; 
v5 = array[11] * v3[1];        
v4[1] = v5; v5 = v3[2] - LOBYTE(array[14]); 
v3[2] = v5; 
v5 = v3[2] - 1; 
v4[2] = v5; v5 = v3[3] + 1;
v3[3] = v5;
v5 = array[21] ^ v3[3]; 
v4[3] = v5;v5 = array[24] * v3[4];
v3[4] = v5;
v5 = v3[4] - LOBYTE(array[27]);
v4[4] = v5; v5 = v3[5] - 1; 
v3[5] = v5; 
v5 = v3[5] - 1;
v4[5] = v5;v5 = array[34] ^ v3[6];
v3[6] = v5;
v5 = v3[6] - LOBYTE(array[37]);
v4[6] = v5;v5 = array[40] + v3[7];
v3[7] = v5; 
v5 = array[43] ^ v3[7];
v4[7] = v5;v5 = v3[8] + 1;
v3[8] = v5;
v5 = v3[8] - 1;
v4[8] = v5; v5 = array[50] * v3[9];
v3[9] = v5;
v5 = array[53] + v3[9]; 
v4[9] = v5;v5 = array[56] + v3[10];
v3[10] = v5;
v5 = array[59] ^ v3[10]; 
v4[10] = v5;v5 = array[62] + v3[11];
v3[11] = v5; 
v5 = array[65] * v3[11];
v4[11] = v5;v5 = array[68] * v3[12];
v3[12] = v5;
v5 = array[71] + v3[12];
v4[12] = v5;v5 = array[74] ^ v3[13];
v3[13] = v5; 
v5 = v3[13] - LOBYTE(array[77]);
v4[13] = v5;v5 = array[80] + v3[14];
v3[14] = v5;
v5 = v3[14] + 1; 
v4[14] = v5;

根据上面每一块内容写脚本计算V3

#include<iostream>
#include<windows.h>
#include<string>
using namespace std;
int main(){unsigned long array[] ={0x0A,0x04,0x10,0x08,0x03,0x05,0x01,0x04,0x20,0x08,0x05,0x03,0x01,0x03,0x02,0x08,0x0B,0x01,0x0C,0x08,0x04,0x04,0x01,0x05,0x03,0x08,0x03,0x21,0x01,0x0B,0x08,0x0B,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x51,0x08,0x04,0x24,0x01,0x0C,0x08,0x0B,0x01,0x05,0x02,0x08,0x02,0x25,0x01,0x02,0x36,0x08,0x04,0x41,0x01,0x02,0x20,0x08,0x05,0x01,0x01,0x05,0x03,0x08,0x02,0x25,0x01,0x04,0x09,0x08,0x03,0x20,0x01,0x02,0x41,0x08,0x0C,0x01,0x07,0x22,0x07,0x3F,0x07,0x34,0x07,0x32,0x07,0x72,0x07,0x33,0x7,0x18,0x7,0xffffffa7,0x7,0x31,0x7,0xfffffff1,0x7,0x28,0x7,0xffffff84,0x7,0xffffffc1,0x7,0x1e,0x7,0x7a};unsigned long v4[] = {0x22,0x3f,0x34,0x32,0x72,0x33,0x18,0xffffffa7,0x31,0xf1,0x28,0xffffff84,0xffffffc1,0x1e,0x7a};unsigned long v3[15];v3[0] = (v4[0] + LOBYTE(array[5])) ^ array[2];v3[1] = (v4[1] / array[11]) ^ array[8];v3[2] = (v4[2] + 1) + LOBYTE(array[14]);v3[3] = (v4[3] ^ array[21]) - 1;v3[4] = (v4[4] + LOBYTE(array[27])) / array[24];v3[5] = (v4[5] + 1) + 1;v3[6] = (v4[6] + LOBYTE(array[37])) ^ array[34];v3[7] = (v4[7] ^ array[43]) - array[40];v3[8] = (v4[8] + 1) - 1;v3[9] = (v4[9] - array[53]) / array[50];v3[10] = (v4[10] ^ array[59]) - array[56];v3[11] = (v4[11] / array[65])  - array[62];v3[12] = (v4[12] - array[71]) / array[68];v3[13] = (v4[13] +  LOBYTE(array[77])) ^ array[74];v3[14] = (v4[14] - 1) - array[80];cout << "flag{";for(int i=0;i<15;i++){cout <<char(v3[i]);}cout<<"}";return 0;
}

在这里插入图片描述
得到 Flag

0x7 总结

这道题不像往常刷的题那样去破解算法本身,由于他分支复杂,所以应该有内在的规律。

这篇关于复盘网鼎杯Re-Signal Writeup的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/458907

相关文章

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

2024年 Biomedical Signal Processing and Control 期刊投稿经验最新分享

期刊介绍 《Biomedical Signal Processing and Control 》期刊旨在为临床医学和生物科学中信号和图像的测量和分析研究提供一个跨学科的国际论坛。重点放在处理在临床诊断,患者监测和管理中使用的方法和设备的实际,应用为主导的研究的贡献。 生物医学信号处理和控制反映了这些方法在工程和临床科学的界面上被使用和发展的主要领域。期刊的范围包括相关的评论论文(review p

013.Python爬虫系列_re正则解析

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈 优

【自用14】C++俄罗斯方块-思路复盘

1.编写主函数 int main(void){welcome();//欢迎函数system("pause");//窗口停留colsegraph();//关闭图画return 0;//返回值} 其中包含有最开始的欢迎,以及基础的窗口停留、图画关闭和返回值语句 2.编写欢迎函数 需求: 欢迎函数中需要包含的功能 设置游戏窗口的大小 设置游戏窗口的颜色 设置游戏窗口需要显示的文字的字

复盘高质量Vision Pro沉浸式视频的制作流程与工具

在探索虚拟现实(VR)和增强现实(AR)技术的过程中,高质量的沉浸式体验是至关重要的。最近,国外开发者Dreamwieber在其作品中展示了如何使用一系列工具和技术,创造出令人震撼的Vision Pro沉浸式视频。本文将详细复盘Dreamwieber的工作流,希望能为从事相关领域的开发者们提供有价值的参考。 一、步骤和工作流 构建基础原型 目的:快速搭建起一个基本的模型,以便在设备

Login failed:make sure your username and password are correct and that you’re an admin or moderator

Login failed:make sure your username and password are correct and that you’re an admin or moderator   1.使用MySql查看工具进入数据库,进入表“ofuser”,把字段 plainPassword 改成 123,然后在你的控制台上输入该表的   username跟plainPa

9月5日复盘日记

9月5日复盘日记 前言今日感恩今日知识今日反思今日名言 前言   昨天空了一天没有进行复盘,但其实昨天效率也挺高,进行了实验的完善、审稿还有每日leetcode的刷题。但为什么昨天不进行记录呢,因为昨天心情比较一般,一整天总感觉有点浮躁,不是很喜欢当下的自己,所以直接刷完题就去外面散了散心,一个人待着真的好舒服(好像也是越来越喜欢一个人了,特别自在,有人打扰的时候会有一些不知所措

【HDU】5958 New Signal Decomposition【离散对数下的FFT】

题目链接:【HDU】5958 New Signal Decomposition 在此先感谢小q对我的指导,没有q老师的帮助,估计永远也做不出来了。 首先我们考虑对这个式子做离散对数。令 g g为pp的某个原根,则有: bi=∑p−1j=0aj⋅r(i,j) \quad b_i=\sum_{j=0}^{p-1}a_j\cdot r(i,j) bi=∑p−1j=0aj⋅2sin32πi⋅j

Java Lock 中使用 await() 和 signal()实现 wait()/notify()机制

** Java Lock 中使用 await() 和 signal()实现 wait()/notify()机制 ** 案例 import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;

Fourier TransformHilbert TransformRelated Function's MATLAB Simulation in Signal Processing

Fourier Transform:对于平稳信号有着明确的物理意义,频域反应各频率成分,可用于滤除高频噪声分量Hilbert  Transform:平稳信号分析,在信号分析和贷通信号中,理论和实用价值,SSB Walsh-Hadamand Transform:基于非正弦正交基的信号变换 ---First Of ALL---在数学与