逆向攻防世界CTF系列27-200simple-check-100
逆向攻防世界CTF系列27-200simple-check-100
巨难受的一题,gdb环境配了半天
32位无壳
这里要check,先跟进下面的interesting_function看看
putchar,这里就是输出,那我们只需要动调将check_key那修改为正确就行
下断点
右上角右键modify成1
但是输出乱码。
查阅资料后可以用gbd动调
环境配了半天
如果是2024-11-11左右安装gbd如果出现报错,可以参考[Kali 2024 逆向调试 GDB 13.2 安装插件 Peda 不兼容报错解决方案_kali安装gdb-CSDN博客](https://blog.csdn.net/qq_51886509/article/details/141227182?ops_request_misc=%7B%22request%5Fid%22%3A%22984C9D72-904C-4F18-B580-8A359D6C46D7%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=984C9D72-904C-4F18-B580-8A359D6C46D7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-2-141227182-null-null.142v100pc_search_result_base4&utm_term=no module named six gdb&spm=1018.2226.3001.4187)
开始
gbd
file task9_x86_64_46d01fe312d35ecf69c4ff8ab8ace75d080891dc
设置断点在main函数入口处
b main
开始运行
r
到这里继续单步执行,一直到test eax,eax那
n
查看eax寄存器值
i r eax
修改eax寄存器值
set $eax=1
修改就行
直接运行至程序结束
c
flag:
flag_is_you_know_cracking!!!
到这,其实还有解法,那就是纯静态分析,来自攻防世界的wp
unsigned int *__cdecl interesting_function(int *a1)
{
unsigned int *result; // eax
unsigned int v2; // [esp+1Ch] [ebp-1Ch] BYREF
unsigned int *v3; // [esp+20h] [ebp-18h]
int *v4; // [esp+24h] [ebp-14h]
int j; // [esp+28h] [ebp-10h]
int i; // [esp+2Ch] [ebp-Ch]
result = (unsigned int *)a1;
v4 = a1;
for ( i = 0; i <= 6; ++i )
{
v2 = v4[i] ^ 0xDEADBEEF;
result = &v2;
v3 = &v2;
for ( j = 3; j >= 0; --j )
result = (unsigned int *)putchar((char)(*((_BYTE *)v3 + j) ^ flag_data[4 * i + j]));
}
return result;
}
这里无非是对flag做处理,enc来自flag_data,都可以获取,要点耐心还是可以解密的
我们不用管check_key,它的作用只是验证,我们目的是输出flag
#include <stdio.h>
unsigned char flag_data[] = {
220, 23, 191, 91, 212, 10, 210, 27, 125, 218,
167, 149, 181, 50, 16, 246, 28, 101, 83, 83,
103, 186, 234, 110, 120, 34, 114, 211 };
char v7[] = {
84, -56, 126, -29, 100, -57, 22, -102, -51, 17,
101, 50, 45, -29, -45, 67, -110, -87, -99, -46,
-26, 109, 44, -45, -74, -67, -2, 106 };
unsigned int v2;
unsigned char* v3;
int main() {
for (int i = 0; i <= 6; ++i) {
v2 = ((v7[4 * i] & 0x000000FF) + ((v7[4 * i + 1] & 0x000000FF) << 8)
+ ((v7[4 * i + 2] & 0x000000FF) << 16) + ((v7[4 * i + 3] & 0x000000FF) <<
24)) ^ 0xDEADBEEF;
v3 = (unsigned char*)&v2;
for (int j = 3; j >= 0; --j) printf("%c", *(v3 + j) ^ flag_data[4 * i + j]);
}
printf("\n");
for (int i = 0; i <= 6; ++i) {
printf("%c", v7[4 * i + 3] ^ 0xDE ^ flag_data[4 * i + 3]);
printf("%c", v7[4 * i + 2] ^ 0xAD ^ flag_data[4 * i + 2]);
printf("%c", v7[4 * i + 1] ^ 0xBE ^ flag_data[4 * i + 1]);
printf("%c", v7[4 * i] ^ 0xEF ^ flag_data[4 * i]);
}
}
解释一下两种解法,第一种是直接模仿源码,第二种其实也是一样不过进一步理解了
第一种先进行处理,原文中的v4[i]其实是4个字节,从循环i<=6也可以猜到,是四个四个处理的
那么第二层循环只是挨个输出而已
第二种方法其实就是直接进行处理,因为是小端字节序,低位在低地址
所以我们看到的v7其实是小端序,我们要给它还原成我们熟知的顺序
for (int j = 3; j >= 0; --j) printf(“%c”, *(v3 + j) ^ flag_data[4 * i + j]);这个其实做的也是逆序
理,因为是小端字节序,低位在低地址
所以我们看到的v7其实是小端序,我们要给它还原成我们熟知的顺序
for (int j = 3; j >= 0; --j) printf(“%c”, *(v3 + j) ^ flag_data[4 * i + j]);这个其实做的也是逆序