当前位置: 首页 > news >正文

re题(49)BUUCTF-crackMe

BUUCTF在线评测

int wmain()
{FILE *v0; // eaxFILE *v1; // eaxchar v3; // [esp+3h] [ebp-405h]char v4[256]; // [esp+4h] [ebp-404h] BYREFchar Format[256]; // [esp+104h] [ebp-304h] BYREFchar v6[256]; // [esp+204h] [ebp-204h] BYREFchar v7[256]; // [esp+304h] [ebp-104h] BYREFprintf("Come one! Crack Me~~~\n");memset(v7, 0, sizeof(v7));                    // 把v7数组重置为0memset(v6, 0, sizeof(v6));                    // 把v6数组重置为0while ( 1 ){do{do                                        // 输入用户名{printf("user(6-16 letters or numbers):");scanf("%s", v7);v0 = (FILE *)sub_4024BE();fflush(v0);}while ( !(unsigned __int8)sub_401000(v7) );printf("password(6-16 letters or numbers):");// 输入密码scanf("%s", v6);v1 = (FILE *)sub_4024BE();fflush(v1);}while ( !(unsigned __int8)sub_401000(v6) );sub_401090(v7);                             // 处理用户名memset(Format, 0, sizeof(Format));memset(v4, 0, sizeof(v4));v3 = ((int (__cdecl *)(char *, char *))loc_4011A0)(Format, v4);if ( (unsigned __int8)sub_401830(v7, v6) )  // 关键:处理用户名和密码{if ( v3 )break;}printf(v4);}printf(Format);return 0;
}

bool __cdecl sub_401830(int a1, const char *a2)
{int v3; // [esp+18h] [ebp-22Ch]int v4; // [esp+1Ch] [ebp-228h]int v5; // [esp+28h] [ebp-21Ch]unsigned int v6; // [esp+30h] [ebp-214h]char v7; // [esp+36h] [ebp-20Eh]char v8; // [esp+37h] [ebp-20Dh]char v9; // [esp+38h] [ebp-20Ch]unsigned __int8 v10; // [esp+39h] [ebp-20Bh]unsigned __int8 v11; // [esp+3Ah] [ebp-20Ah]char v12; // [esp+3Bh] [ebp-209h]int v13; // [esp+3Ch] [ebp-208h] BYREFchar v14; // [esp+40h] [ebp-204h] BYREFchar v15[255]; // [esp+41h] [ebp-203h] BYREFchar v16[256]; // [esp+140h] [ebp-104h] BYREFv4 = 0;v5 = 0;v11 = 0;v10 = 0;memset(v16, 0, sizeof(v16));                  // 重置v15v14 = 0;memset(v15, 0, sizeof(v15));                  // 重置v16,定义的变量就这两个数组,肯定用来加密密码v9 = 0;v6 = 0;v3 = 0;while ( v6 < strlen(a2) ){if ( isdigit(a2[v6]) )                      // 检查字符是否是十进制数字{v8 = a2[v6] - 48;                         // 把字符变成整数类型}else if ( isxdigit(a2[v6]) )                // 看一个字符是否是十六进制数字{if ( *((_DWORD *)NtCurrentPeb()->ProcessHeap + 3) != 2 )// 这里是反调试操作,如果处于调试状态就会执行if里的赋值操作a2[v6] = 34;v8 = (a2[v6] | 0x20) - 87;                // 把字符型变成整形十六进制形式}else{v8 = ((a2[v6] | 0x20) - 97) % 6 + 10;     // 其他小写处理后,%6+10}__rdtsc();                                  // __rdtsc 指令被连续使用两次,但并没有对其返回值进行存储或使用,这种情况可能是为了引入一些延迟,或者是代码在开发过程中用于性能测试__rdtsc();v9 = v8 + 16 * v9;                          // 作用是把密码中每两个字符转换成整形十六进制存放在v15中if ( !((int)(v6 + 1) % 2) ){v15[v3++ - 1] = v9;                       // 这个while是生成v15数组,因为整个while只有这里有v15v9 = 0;}++v6;}while ( v5 < 8 ){v10 += byte_416050[++v11];v12 = byte_416050[v11];v7 = byte_416050[v10];byte_416050[v10] = v12;byte_416050[v11] = v7;if ( (NtCurrentPeb()->NtGlobalFlag & 0x70) != 0 )// 同样是反调试v12 = v10 + v11;v16[v5] = byte_416050[(unsigned __int8)(v7 + v12)] ^ v15[v4 - 1];// byte数组和密码经过处理得到的v15数组异或,再赋值给v16数组,意思是v16是加密后的密码if ( (unsigned __int8)*(_DWORD *)&NtCurrentPeb()->BeingDebugged )// 同样反调试{v10 = -83;v11 = 43;}sub_401710(v16, a1, v5++);                  // 只有这里用到了用户名数组,其他地方都是处理密码,而用户名我们知道,所以不用管v4 = v5;if ( v5 >= (unsigned int)(&v15[strlen(&v14)] - v15) )v4 = 0;}v13 = 0;sub_401470(v16, &v13);                        // 从这个函数里我们可以知道v16数组的数据return v13 == 0xAB94;
}

所以只要找到byte数组的值就可以了,而byte数组是动态分配的,所以需要动态调试(用OD或者ida本地调试都可以)

那么如何用动态调试找byte数组呢?

首先看ida这个位置的汇编代码

可以看到这个关键的异或操作,而异或操作上面有两个mov操作,ecx里存的就是我们要的byte数组,看看它的地址是00401B3E

 

这个文件的OEP(入口)是00401000,我们算出xor操作偏移值是00401B3E-00401000=B3E

打开OD,我这里入口是000E1000,可以算出xor操作的地址是000E1000+B3E=000E1B3E

在xor这里右键--断点--切换就下好断点了,如果直接执行我们是得不到正确的byte数组的,因为遗漏了反调试操作,我们需要把if语句里的内容nop掉(不进行任何操作的指令)

用找xor指令位置同样的方法找到三个反调试操作

第一个反调试的位置已经找到,我们把选中的指令nop掉

点用nop填充

填充完是这个效果

其他两个反调试同样操作

nop掉后点运行,或F9快捷方式

输入用户名密码

红框里我们可以看到ecx的值,按F9继续可以得到byte的数据

byte_416050 的值为0x2A, 0xD7, 0x92, 0xE9, 0x53, 0xE2, 0xC4, 0xCD
 

写个脚本

#include <bits/stdc++.h>
using namespace std;
int a[] = {0x2A, 0xD7, 0x92, 0xE9, 0x53, 0xE2, 0xC4, 0xCD};
string s = "dbappsec";
int main() {for (int i = 0; i < 8; i++) {int num = (int)s[i]; int ans = num ^ (int)a[i];    //异或回去得到原密码cout << hex << ans;}return 0;
}

最后进行 md5 加密,取 32 位小写,得到 flag

flag{d2be2981b84f2a905669995873d6a36c}

http://www.xdnf.cn/news/193681.html

相关文章:

  • 【深度剖析】贵州茅台的数字化转型(2025)(中1)
  • Spring的BeanFactory和FactoryBean的区别
  • springboot dev process
  • JVM模型、GC、OOM定位
  • [250428] Nginx 1.28.0 发布:性能优化、安全增强及新特性
  • wps批注线条怎么取消去掉wps批注后有竖线
  • CentOS7——Docker部署java服务
  • 基于常微分方程的神经网络(Neural ODE)
  • 如何通过Google Chrome增强网页内容的安全性
  • 低空经济无人机创新实训室解决方案
  • 亚马逊环保标识运营指南:抢占流量新赛道的6大策略解析
  • 读论文《Deep learning-assited pulsed discharge plasma catalysis modeling》2023 ECM
  • Android Studio 2024版,前进返回按钮丢失解决
  • springboot项目之websocket的坑:spring整合websocket后进行单元测试后报错的解决方案
  • Qt6.8.2中WebAssembly沙盒环境中预加载文件
  • Cursor
  • 可视化图解算法:合并二叉树
  • JVM 生产环境问题定位与解决实战(八):实战篇——正则表达式回溯引发的CPU 100%
  • C++20 小语法
  • 【KWDB 创作者计划】_KWDB产品技术解读
  • 【线性规划】对偶问题的实际意义与重要性质 学习笔记
  • 鼠标获取坐标 vs 相机获取坐标
  • SpringBoot应用原生或docker镜像容器集成Skywalking
  • 数据要素与居民就业的深层联结 数字化转型下的劳动力市场变革
  • 项目上线流程梳理(Linux宝塔面板)
  • 基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
  • Web基础与HTTP协议
  • 第二章、Isaaclab强化学习包装器(1)
  • 研究:大模型输出一致性:确定性与随机性的场景化平衡
  • 【Android】SettingsPreferenceService