文章目录
- 一.sum
- 1. 分析程序逻辑
- 2.解数独矩阵
- 3.解题脚本
- 二.Poisoned_tea_CHELL
- 1. 重新识别函数及程序逻辑分析
- 2.IDA动态调试(attach附加调试)
- 3. 输入选项进行单步调试
- 4.解题脚本
- BWBA
- OldSymbolicCode
一.sum
1. 分析程序逻辑
这里直接贴上当时分析的结果,根据程序行为不难猜出是数独问题(还得靠猜)
main:
int __cdecl main(int argc, const char **argv, const char **envp)
{char *mart; // rbpint flagValue; // r14dint sum; // r12d__int64 i; // rbxchar chr; // alint tmp; // eaxchar *md5str; // raxmart = matrix;flagValue = 1;sum = 0;puts("Welcome to Solver!");do{for ( i = 0LL; i != 9; ++i ){if ( !mart[i] ) // 如果矩阵元素为零则输入字符{chr = getchar();if ( (chr - '1') > 8u ) // 所以输入的必须是数字,否则错误flagValue = 0;elsemart[i] = chr - '0'; // 数字}tmp = mart[i];sum += tmp;}mart += 9; // 一次处理九个字符}while ( mart != &matrix[81] ); // 一共81if ( flagValue && verify() ) // 盲猜是数独{puts("You Win!");__snprintf_chk(buf, 32LL, 1LL, 32LL, "%d"); // 405md5str = str2md5(buf, strlen(buf));__printf_chk(1LL, "flag is: flag{%s}\n\n", md5str);// flag{bbcbff5c1f1ded46c25d28119a85c6c2}exit(0);}puts("Again~");return 0;
}
verify(验证):
尤其是当时看到九个一组以及按列检查就反应过来应该是数独
__int64 verify()
{char *matr; // rsi__int64 j; // rcx_DWORD *CHECK; // rdi__int64 tmp; // rdichar *matr2; // rsi__int64 k; // rcx_DWORD *check2; // rdi__int64 chr; // rdi__int64 iii; // r8char *matr3; // r9__int64 len3; // rcx_DWORD *check3; // rdiint cout; // r10dchar *matr4; // rdi__int64 i; // rcx__int64 tmpchr; // rbxmatr = matrix;
LABEL_2:j = 10LL;CHECK = check;while ( j ){*CHECK++ = 0; // 初始化空间--j;}while ( 1 ){tmp = matr[j];if ( check[tmp] ) // 不能访问已访问过的return 0LL;++j;check[tmp] = 1; // 置一if ( j == 9 ){matr += 9; // 九个一组if ( matr != &matrix[81] )goto LABEL_2;matr2 = matrix;
LABEL_9:k = 10LL;check2 = check;while ( k ){*check2++ = 0; // 再次清空check数组--k;}while ( 1 ){chr = matr2[9 * k]; // 检查第一列if ( check[chr] )return 0LL;++k;check[chr] = 1;if ( k == 9 ){if ( ++matr2 != &matrix[9] )goto LABEL_9;iii = 0LL;while ( 2 ){ // 检查第二列matr3 = &matrix[iii];do{len3 = 10LL;check3 = check;cout = 3;while ( len3 ) // 清空check{*check3++ = 0;--len3;}matr4 = matr3;while ( 2 ){for ( i = 0LL; i != 3; ++i ){tmpchr = matr4[i];if ( check[tmpchr] ) // 也是不能有1return 0LL;check[tmpchr] = 1;}matr4 += 9;if ( --cout )continue;break;}matr3 += 3;}while ( matr3 != &matr2[iii] );iii += 27LL;if ( iii != 81 )continue;break;}return 1LL;}}}}
}
2.解数独矩阵
先跟进martix然后将数据读取出来
然后询问ChatGpt直接得到答案
以及给出解题代码和运行结果:
然后填数独就可以过了
3.解题脚本
#include<stdio.h>
int main()
{int sum = 0;unsigned char matrix[81] ={5, 3, 0, 0, 7, 0, 0, 0, 0, 6,0, 0, 1, 9, 5, 0, 0, 0, 0, 9,8, 0, 0, 0, 0, 6, 0, 8, 0, 0,0, 6, 0, 0, 0, 3, 4, 0, 0, 8,0, 3, 0, 0, 1, 7, 0, 0, 0, 2,0, 0, 0, 6, 0, 6, 0, 0, 0, 0,2, 8, 0, 0, 0, 0, 4, 1, 9, 0,0, 5, 0, 0, 0, 0, 8, 0, 0, 7,9};int grid[81] = {5, 3, 4, 6, 7, 8, 9, 1, 2,6, 7, 2, 1, 9, 5, 3, 4, 8,1, 9, 8, 3, 4, 2, 5, 6, 7,8, 5, 9, 7, 6, 1, 4, 2, 3,4, 2, 6, 8, 5, 3, 7, 9, 1,7, 1, 3, 9, 2, 4, 8, 5, 6,9, 6, 1, 5, 3, 7, 2, 8, 4,2, 8, 7, 4, 1, 9, 6, 3, 5,3, 4, 5, 2, 8, 6, 1, 7, 9};int len = 0;for (int i = 0; i < 81; i++){if (!matrix[i]){len++;printf("%d", grid[i]);//输出需要填充的序列//468912723481342575971422657913948591537428763345261}}return 0;
}
linux下运行程序,输入序列:468912723481342575971422657913948591537428763345261
即可得到答案:
二.Poisoned_tea_CHELL
1. 重新识别函数及程序逻辑分析
这里可能是识别问题,找到这三块红色区域查看汇编
然后可以发现这里莫名其妙定义了四个字节数据,按u取消掉下方指令定义
然后从这段数据头(0x763处)按p识别为函数,即可可以看到tea逻辑
另外两块红色区域同理,重新识别后可以看到主函数(如果看不到那就对tea函数交叉引用向上找)
这里给出我分析美化后的主函数:
不过这里有一个关键问题就是他的key和关键数据并不能通过静态分析看到,所以需要动态分析了
__int64 __fastcall Main()
{__int64 result; // raxint i; // [rsp+Ch] [rbp-464h]int j; // [rsp+10h] [rbp-460h]int chr1; // [rsp+14h] [rbp-45Ch] BYREFint chr2; // [rsp+18h] [rbp-458h]int v5; // [rsp+1Ch] [rbp-454h]int key[8]; // [rsp+20h] [rbp-450h] BYREFint d1; // [rsp+40h] [rbp-430h]int d2; // [rsp+44h] [rbp-42Ch]int b1; // [rsp+48h] [rbp-428h]int b2; // [rsp+4Ch] [rbp-424h]int v11; // [rsp+50h] [rbp-420h]int buffer[258]; // [rsp+60h] [rbp-410h] BYREFunsigned __int64 v13; // [rsp+468h] [rbp-8h]v13 = __readfsqword(0x28u);key[0] = 5;key[1] = 2;key[2] = dword_7FA16F6F8464; // 猜测也是一位数,可以爆破key[3] = dword_7FA16F6F8454;key[4] = 0;memset(buffer, 0, 0x400uLL);sub_7FA16F6F5524();sub_7FA16F6F5554();sub_7FA16F6F5594(); // 这几个函数找不到sub_7FA16F6F5574(&unk_7FA16F6F6469, buffer);chr1 = 0;chr2 = 0;v5 = 0;for ( i = 0; buffer[i]; i += 2 ) // 也就是每次对buffer的两个字符进行tea加密{chr1 = buffer[i];chr2 = buffer[i + 1];Tea(dword_7FA16F6F8474, &chr1, key); // 一次加密两个字符buffer[i] = chr1; // 更新buffer串buffer[i + 1] = chr2;}d1 = 0;d2 = 0;b1 = 0;b2 = 0;v11 = 0;for ( j = 0; buffer[j]; j += 2 ) // 比较函数{d1 = desStr[j];d2 = desStr[j + 1];b1 = buffer[j];b2 = buffer[j + 1];if ( d1 != b1 || d2 != b2 )break;}sub_7FA16F6F5524();result = 0LL;if ( v13 != __readfsqword(0x28u) )return sub_7FA16F6F5544();return result;
}
2.IDA动态调试(attach附加调试)
如果直接使用ida远程动调会提示错误:
Input file is a dynamic library, it cannot be run by itself.
Please specify the host application (Debugger, Process options)
提示这是个动态库文件,需要附加进程进行调试,那么我们可以使用IDA的附加调试功能
- linux虚拟机使用root权限运行ida的linux_server64
必须使用root权限,否则后续附加调试会失败,这是由于IDA服务端的权限不够
- 运行程序
- 附加调试
Debugger>Attach to process
然后找到毒tea进程,双击即可
选择same
3. 输入选项进行单步调试
成功附加后会发现按f7或者f8都没反应,此时程序等待输出,先到linux虚拟机输入一个选项
如果输入1,后续调试比较难找,总之就是找到Loading字符串,注意不能跳过了
(直接搜索字符串搜索不到,这题应该是有SMC的操作对程序代码进行解密)
下方的call sun_7f006f7c2536就是主函数,跟进重新识别即可看到逻辑(这里不做详细介绍,以选项2为主)
如果输入2
一直按f7,最后可以发现程序会卡住,并且还能看见InputFlag字符串,这里就是主函数了
往上翻找到起始地址,对loc_loc_7F3BB0FB6536按p识别为函数就可以看到主函数逻辑了
然后还有一些没有被正确识别的函数,需要手动跟进按p识别为函数,然后回到反汇编界面按f5重新识别即可
key的值:
tea加密循环次数的值(所以这个tea循环36次而非32次):
加密后的data,跟进可以提取出数据
4.解题脚本
#include<stdio.h>
void Tea(int len, unsigned int* buffer, int* key)
{int i; // [rsp+24h] [rbp-14h]unsigned int v5; // [rsp+28h] [rbp-10h]unsigned int v6; // [rsp+2Ch] [rbp-Ch]unsigned int v7; // [rsp+30h] [rbp-8h]v5 = *buffer;v6 = buffer[1];v7 = 0xd9b6d99c;for (i = 0; i < len; ++i){v6 -= (v5 + ((v5 >> 5) ^ (16 * v5))) ^ (key[(v7 >> 11) & 3] + v7);v7 += 0x41104111;v5 -= (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (key[v7 & 3] + v7);}*buffer = v5;buffer[1] = v6;
}
int main()
{int buffer[14] ={-318921983,1639894517,-1197577091,-835265432,1265521566,1680782596,1425658684,1829167973,-360235693,-1537112825,-676229584,-1000652734,0,0,};int key[5] = { 5,2,9,7,0 };int chr[2] = { 0 };for (int i = 0; buffer[i]; i += 2) // 也就是每次对buffer的两个字符进行tea加密{chr[0] = buffer[i];chr[1] = buffer[i + 1];Tea(36, chr, key); // 一次加密两个字符buffer[i] = chr[0]; // 更新buffer串buffer[i + 1] = chr[1];}unsigned char* p = (unsigned char*)buffer;printf("%s", p);//Thisisflag{cdfec405-3f4b-457e-92fe-f6446098ee2e}return 0;
}
BWBA
简单分析了一下程序逻辑
这里复现时询问ChatGpt回答我的是FFT算法,而不是DCT,让其输出解密脚本也一直错误,看来还是得多了解一下这个算法
参考大佬文章:2023春秋杯春季赛WP-REVERSE(AK)
能用cv2库函数进行处理
import numpy as np
import cv2x = np.array([370.75,234.362,-58.0834,59.8212,88.8221,-30.2406,21.8316,49.9781,-33.5259,2.69675,43.5386,-30.2925,-28.0754,27.593,-2.53962,-27.1883,-5.60777,-0.263937,6.80326,8.03022,-6.34681,-0.89506,-6.80685,-13.6088,27.0958,29.8439,-21.7688,-20.6925,-13.2155,-37.0994,2.23679,37.6699,-3.5,9.85188,57.2806,13.5715,-20.7184,8.6816,3.59369,-4.5302,4.22203,-28.8166,-23.695,31.2268,6.58823,-39.9966,-20.7877,-19.7624,-22.031,16.3285,2.07557,-26.2521,16.1914,18.3976,-26.9295,3.03769,41.0412,20.2598,14.991,6.99392,-22.3752,-7.24466,8.96299,-10.4874], dtype=np.float64)
x = cv2.idct(x)
x = x.ravel()
flag=''for i in range(len(x)):flag+=chr(round(x[i]))
print(flag)#flag{9ab488a7-5b11-1b15-04f2-c230704ecf72}
关于DCT算法这几篇文章不错:
- DCT离散余弦变换
- 详解离散余弦变换(DCT)