完成这题就是一个全新的突破
目录
步骤1:找到flag的位置
网上其他人直接怼函数,说那个函数是关键函数。。
我看的莫名其妙,一脸懵逼
正确的方式先是搜索flag,再进去
ctrl+x寻找出处,然后进去,就到了关键函数里
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]
v11 = __readfsqword(0x28u);
*(_QWORD *)src = 0x534C43444ELL;
v7 = 0LL;
v8 = 0;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
v10 = 0;
text = (char *)join(key3, v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
printf("Please input your flag:");
while ( 1 )
{
v1 = getchar();
if ( v1 == 10 )
break;
if ( v1 == 32 )
{
++v2;
}
else
{
if ( v1 <= 96 || v1 > 122 )
{
if ( v1 > 64 && v1 <= 90 )
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
}
else
{
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
if ( !(v3 % v5) )
putchar(32);
++v2;
}
}
if ( !strcmp(text, str2) )
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v11;
}
步骤2:代码整理
代码整理需要经验,我整理了一个下午,做得少,不熟悉,没办法
其实倒也不难
#include<stdio.h>
char * join(const char * key3,const char * v9){
// 定义两个变量用来接收字符串长度
size_t v2;
size_t v3;
char * dest; // 字符串指针,等一下用来拼接字符串
v2 = strlen(key3);
v3 = strlen(v9);
dest = (char *)malloc(v2+v3+1); // 动态分配内存,记得+1,给\0位置,不然就有可能出错
strcpy(dest,key3); // 复制进去
strcat(dest,v9); // 拼接一下
return dest;
}
int main(){
char v9[] = "hadow"; // 16进制翻译成ascii码,踩坑1
char key3[] = "kills"; // 双击进去就能看到
char key1[] = "ADSFK"; // 双击进去就能看到
char key[100]; // 等下用来放东西,先随便给一个容量
char src[] = "NDCLS"; // 16进制翻译成ascii码,踩坑2
int v2 = 0;
int v3 = 0;
char str2[100]; // 等下用来放东西,先随便给一个容量
// 拼接key3和v9,得到:killshadow
char * text = (char *)join(key3,v9);
strcpy(key,key1); // 复制给key
strcat(key,src); // 拼接给key
// 此时key的值:ADSFKNDCLS
int v5 = strlen(key); // 10
// 循环0-9,10次,因为是常量10,所以是固定的
for(int i = 0;i < v5; ++i){
// 0%10=0,1%10=1…… 所以就是key[0] - key[9]
// 就是key里面每一个字符必定符合条件,必定转成小写
if(key[v3%v5] > 64 && key[v3 % v5] <= 90){
key[i] = key[v3 % v5] + 32; // 转成小写
}
++v3;
}
// 此时v3是10,key:adsfkndcls
// 开启无限循环
while(1){
// 输入东西,都不是exe,跑不了,废的
int v1 = getchar();
// 好像是废话可以省略,进不到这个条件判断里面
if (v1 == 10){
break;
}
// 好像是废话可以省略,进不到这个条件判断里面
if(v1 == 32 ){ // 对应是空格
++v2;
}
else{
// 大写的情况下进入
if( v1 <= 96 || v1 > 122){
// 废话:确保是A-Z
if( v1 > 64 || v1 <= 90){
// 关键算法 ,此时v3是10,所以 10 % 10=0,11 % 10=1
// 也就是key[0]-key[9]遍历
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
else{
// 关键算法
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
}
// 没有意义
if( !(v3 % v5)){
putchar(32);// 没有意义
}
++v2;
}
}
}
// 此时,text:killshadow
if (!strcmp(text,str2)){
puts("成功啦");
}
else{
puts("失败啦");
}
return 0;
}
步骤3:优化删减代码
还原了算法,之后
就整理一下代码,把废话代码删掉,自行优化一下
#include<stdio.h>
char * join(const char * key3,const char * v9){
// 定义两个变量用来接收字符串长度
size_t v2;
size_t v3;
char * dest; // 字符串指针,等一下用来拼接字符串
v2 = strlen(key3);
v3 = strlen(v9);
dest = (char *)malloc(v2+v3+1); // 动态分配内存,记得+1,给\0位置,不然就有可能出错
strcpy(dest,key3); // 复制进去
strcat(dest,v9); // 拼接一下
return dest;
}
int main(){
char v9[] = "hadow"; // 16进制翻译成ascii码,踩坑1
char key3[] = "kills"; // 双击进去就能看到
char key1[] = "ADSFK"; // 双击进去就能看到
char key[100]; // 等下用来放东西,先随便给一个容量
char src[] = "NDCLS"; // 16进制翻译成ascii码,踩坑2
int v2 = 0;
int v3 = 0;
char str2[100]; // 等下用来放东西,先随便给一个容量
// 拼接key3和v9,得到:killshadow
char * text = (char *)join(key3,v9);
strcpy(key,key1); // 复制给key
strcat(key,src); // 拼接给key
// 此时key的值:ADSFKNDCLS
int v5 = strlen(key); // 10
// 循环0-9,10次,因为是常量10,所以是固定的
for(int i = 0;i < v5; ++i){
// 0%10=0,1%10=1…… 所以就是key[0] - key[9]
// 就是key里面每一个字符必定符合条件,必定转成小写
key[i] = key[i] + 32; // 转成小写
}
// 此时v3是10,key:adsfkndcls
// 开启无限循环
while(1){
// 先随便给一个数值吧
int v1 = 67;
// 大写的情况下进入
if( v1 <= 96 || v1 > 122){
// 关键算法 ,此时v3是10,所以 10 % 10=0,11 % 10=1
// 也就是key[0]-key[9]遍历
// 字符数组str2也是遍历存进去
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
++v3;
++v2;
}
}
// 此时,text:killshadow
if (!strcmp(text,str2)){
puts("成功啦");
}
else{
puts("失败啦");
}
return 0;
}
需要str2等于text,那么就需要v1的配合,因为key的内容是固定的
只有v1是变量,就是我们输入的东西,就是flag
步骤4:爆破解题
那解题其实也很好解,范围都固定了是大写字母,就是65-90整数
那就固定公式,暴力破解,针对text的单个字符进行判断是否相等就可以了
#include <stdio.h>
int main(){
// char key[] = "ADSFKSLCDN"; // 原始状态
int flag ;
char key[] = "adsfkndcls"; // 这里转成小写是因为源代码先有循环把大写转成小写了
char text[] = "killshadow"; // text:killshadow
int res = 0;
// 循环常量key数组
for(int i = 0; i<strlen(key); i++){
// 循环变量
for(flag=65; flag<=90; flag++){
res = (flag - 39 - key[i] + 97) %26 +97;
if(res==text[i]){
printf("%c",flag);
}
}
}
return 0;
}
这里写法就是固定循环key,flag遍历 65 - 90,就是A-Z
避坑指南:反过来翻译ascii码
上面注释的踩坑点1和2都是同一个问题
这种东西一开始以为是存int进去,还以为弄这么大干嘛,后来才知道是字符串
那需要怎么翻译呢?
拉去AI翻译一下就可以了
好了,坑来了,目前不知道具体什么原因,需要反过来翻译才可以
就是:68 61 64 6F 77
就是hadow才是正确的,所以啊这个坑有点神奇,
根据我的知识了解,可能是跟CPU生产厂家有关
他们是规定要反着来的,但那是在OD在内存是要反过来
没想到这里也要反过来
觉得我写得好,记得点赞+评论一下噢