BUUCTF逆向工程第一页部分题目
easyre
这题很水,拖进IDA就可以解出来
很明显,flag:flag{this_Is_a_EaSyRe}
reverse1
拖进IDA发现只有这么个东西
所以果断shift+F12从字符串寻找突破口,得到:
跟进可以进入到真正的主程序:
不难发现它将输入和Str2进行比较,并且在前面将Str2中的o变成了0,跟进Str2可以看见:
得到flag:flag{hell0_w0rld}
reverse2
比上一题仁慈,拽进IDA直接可以看代码:
将输入和flag作比较,并在之前把r和i变成1,跟进看见flag是:
得到flag:flag{hack1ng_fo1_fun}
内涵的软件
打开IDA可以看见v5这个抽象的玩意儿:
没错,这货就是答案,flag:flag{49d3c93df25caad81232130f3d2ebfad}
说实话,我不理解这题存在的意义
新年快乐
exeinfoPE告诉我它有壳并且可以使用自带的upx -d解决,所以就解决一下:
在拖入IDA可以看见主程序:
通过我们在小学二年级就学会的代码,可以读出来flag:flag{HappyNewYear!}
xor
拖进IDA可以看见:
它对输入进行了一通异或操作并且与global进行比较,将global提取出来异或回去即可:
#include <iostream>
using namespace std;
int main()
{
int key[99] = {
102, 10, 107, 12, 119, 38, 79, 46, 64, 17,
120, 13, 90, 59, 85, 17, 112, 25, 70, 31,
118, 34, 77, 35, 68, 14, 103, 6, 104, 15,
71, 50, 79, 0};
int i;
for(i = 32; i >= 1; i--)
{
key[i] ^= key[i-1];
}
for(i = 0; i <= 32; i++)
{
cout << char(key[i]);
}
return 0;
}
得到flag:flag{QianQiuWanDai_YiTongJiangHu}
reverse3
IDA里看见它对输入做了sub_4110BE操作,然后又做了一个简单的加法,最后和Str2比较:
点进sub_4110BE可以看见这么个抽象的东西:
看出这东西是个base64加密,搞一搞:
#include <iostream>
using namespace std;
int main()
{
int key[99] = {
101, 51, 110, 105, 102, 73, 72, 57, 98, 95,
67, 64, 110, 64, 100, 72};
int i;
for(i = 0; i <= 15; i++)
{
key[i] -= i;
cout << char(key[i]);
}
return 0;
}
#include <iostream>
#include <cstring>
using namespace std;
char base64[50];
char base64char[100];
int __cdecl base64_decode(char *base64, char *originChar)
{
int v2; // eax
int v3; // eax
int v4; // eax
unsigned __int8 temp[4]; // [rsp+23h] [rbp-Dh] BYREF
unsigned __int8 k; // [rsp+27h] [rbp-9h]
int j; // [rsp+28h] [rbp-8h]
int i; // [rsp+2Ch] [rbp-4h]
i = 0;
j = 0;
while ( base64[i] )
{
memset(temp, 255, sizeof(temp));
for ( k = 0; k <= 0x3Fu; ++k )
{
if ( base64char[k] == base64[i] )
temp[0] = k;
}
for ( k = 0; k <= 0x3Fu; ++k )
{
if ( base64char[k] == base64[i + 1] )
temp[1] = k;
}
for ( k = 0; k <= 0x3Fu; ++k )
{
if ( base64char[k] == base64[i + 2] )
temp[2] = k;
}
for ( k = 0; k <= 0x3Fu; ++k )
{
if ( base64char[k] == base64[i + 3] )
temp[3] = k;
}
v2 = j++;
originChar[v2] = (temp[1] >> 4) & 3 | (4 * temp[0]);
if ( base64[i + 2] == 61 )
break;
v3 = j++;
originChar[v3] = (temp[2] >> 2) & 0xF | (16 * temp[1]);
if ( base64[i + 3] == 61 )
break;
v4 = j++;
originChar[v4] = temp[3] & 0x3F | (temp[2] << 6);
i += 4;
}
return j;
}
int main()
{
char de64[50];
int i;
strcpy(base64, "e2lfbDB2ZV95b3V9");//密文
strcpy(base64char, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");//秘钥
base64_decode(base64, de64);
for(i = 0; i <= strlen(base64); i++)
{
cout << de64[i];//明文
}
return 0;
}
得到flag:flag{i_l0ve_you}
不一样的flag
拖进IDA看见这个,可以推断是个迷宫题:
在最后可以看到结束条件是走到#
根据整体代码判断v3[25]是用来控制层数的,通过查阅v3的地址(00000035)和v7的地址(0000000C)恰好相差41可以推断最后它用来判断的v7就是v3,因此它的地图长这个样子:
*1111
01000
01010
00010
1111#
得到flag:flag{222441144222}
SimpleRev
打开IDA发现主要的加密在Decry函数中:
前面一段生成了key和text:
这里理论上下断点动调就可以得到最终结果,但是我动调会告诉我出现了一个奇奇怪怪的错误,所以我只好手动生成了,其中.elf采用逆序存储,因此需要反向解析:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
long long v9 = 0x776F646168;//hadow
long long src = 0x534C43444E;//NDCLS
int i;
for(i = 0; i <= 4; i++)
{
cout << char(*((const char*)&v9 + i));
}
cout << endl;
for(i = 0; i <= 4; i++)
{
cout << char(*((const char*)&src + i));
}
return 0;
}
得到
text = "killshadow"
key = "adsfkndcls"
接下来就是依据输入对Str2进行操作:
可以写个深搜找到答案;
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
string text = "killshadow";
string key = "adsfkndcls";
int i, j, k;
int v5 = key.size();
int tmp;
for(i = 0; i <= 9; i++)
{
for(j = 65; j <= 122; j++)
{
if((j >= 'a' && j <= 'z') || (j >= 'A' && j <= 'Z'))
{
tmp = (j - 39 - key[i] + 97) % 26 + 97;
if(tmp == text[i])
{
cout << char(j);
break;
}
}
}
}
return 0;
}
得到flag:flag{KLDQCUDFZO}
其实这个地方很明显每一个大写输入其实都可以用一个小写字母代替,也可以达到相同的效果,这样的输入是efxkwoxzti。但是我不理解这题后续也没有相应的验证部分,为什么可以直接用大写的输入。。。
[GXYCTF2019]luck_guy
这题点进去发现它会根据随机数除以200的余数进行操作:
但是随机数嘛,多半是假的,所以可以猜测一下他会按照case4,case5,case1的顺序运行,考虑到elf的逆序存储,搞一个脚本:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
long long a = 0x7F666F6067756369;
int i;
char key2[99] = "";
char key1[99] = "GXY{do_not_";
for(i = 0; i <= 7; i++)
{
key2[i] = char(*((const char*)&a + i));
if(key2[i] % 2 == 1)
{
key2[i] -= 2;
}
else
{
key2[i]--;
}
}
strcat(key1, key2);
cout << key1;
return 0;
}
得到flag:flag{do_not_gase_me}
[BJDCTF2020]JustRE
拖进IDA里看见代码很抽象,所以shift+F12找到这个:
跟进可以看见这个:
得到flag:flag{1999902069a45792d233ac}
[ACTF新生赛2020]easyre
这题有壳,但是upx -d可以解决,所以脱以下子:
进去看见这个:
发现v10和v6应当是连在一起的,给他们make array一下:
之后使用我们在小学二年级就会的知识写个代码:
#include <iostream>
using namespace std;
int main()
{
int key[99] = {126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
116, 115, 114, 113, 112, 111, 110, 109, 108, 107,
106, 105, 104, 103, 102, 101, 100, 99, 98, 97,
96, 95, 94, 93, 92, 91, 90, 89, 88, 87,
86, 85, 84, 83, 82, 81, 80, 79, 78, 77,
76, 75, 74, 73, 72, 71, 70, 69, 68, 67,
66, 65, 64, 63, 62, 61, 60, 59, 58, 57,
56, 55, 54, 53, 52, 51, 50, 49, 48, 47,
46, 45, 44, 43, 42, 41, 40, 39, 38, 37,
36, 35, 32, 33, 34};
char ans[99] = "*F'\"N,\"(I?+@";
int i, j;
for(i = 0; i <= 11; i++)
{
for(j = 0; j <= 94; j++)
{
if(ans[i] == key[j])
{
cout << char(j + 1);
}
}
}
return 0;
}
得到flag:flag{U9X_1S_W6@T?}
[ACTF新生赛2020]rome
拖进IDA进行一个array的make和一个名字的改,得到这个东西:
在进行一个代码的写:
#include <iostream>
using namespace std;
int main()
{
char key[99] = "Qsw3sj_lz4_Ujw@l";
int i, j, tmp;
bool f;
for(i = 0; i <= 15; i++)
{
f = true;
for(j = 65; j <= 122; j++)
{
if(j >= 'A' && j <= 'Z')
{
tmp = (j - 51) % 26 + 65;
}
if(j >= 'a' && j <= 'z')
{
tmp = (j - 79) % 26 + 97;
}
if(tmp == key[i])
{
f = false;
cout << char(j);
}
}
if(f == true)
{
cout << key[i];
}
}
return 0;
}
得到flag:flag{Cae3ar_th4_Gre@t}
[2019红帽杯]easyRE
起始函数很抽象,shift+F12寻找特征字符串,跟进发现:
它做了10次base64加密,经过解密得到:“https://bbs.pediy.com/thread-254172.htm”
好,被骗了。。。
开始往前搜索信息:
把这一坨东西给他异或回去得到:Info:The first four chars are `flag`
怎么说呢,既有用,又没用。。。
不过在跟进off_6CC090中发现了这两个被函数调用过的给定数组:
跟进函数看见:
解读出v4这个东西异或之后首位是f,末位是g,推测整体异或之后是“flag”,反向把v4解出来,再讲for循环异或回去:
#include <iostream>
using namespace std;
int main()
{
int ans[99] =
{
64, 53, 32, 86, 93, 24, 34, 69, 23, 47,
36, 110, 98, 60, 39, 84, 72, 108, 36, 110,
114, 60, 50, 69, 91
};
int i, tmp;
int key[5];
char s[5] = "flag";
for(i = 0; i <= 3; i++)
{
key[i] = ans[i] ^ s[i];
}
for(i = 0; i <= 24; i++)
{
tmp = ans[i] ^ key[i % 4];
cout << char(tmp);
}
return 0;
}
得到flag:flag{Act1ve_Defen5e_Test}
题出的很好,下次不要出了。
[GUET-CTF2019]re
有壳,但是可以upx -d:
点进去通过shift+F12获取关键字,跳转到:
点进sub_4009AE函数,它会让你做32个乘法题,鼓捣鼓捣发现a1[6]不见了,所以爆破一下得到flag:flag{e165421110ba03099a1c039337}
[WUSTCTF2020]level1
拖进IDA发现:
再根据提供的输出文档,写一个简单的代码:
#include <iostream>
using namespace std;
int main()
{
long long ans[99] = {0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000};
int i;
for(i = 1; i <= 19; i++)
{
if((i & 1) == 0)
{
cout << char(ans[i] / i);
}
else
{
cout << char(ans[i] >> i);
}
}
return 0;
}
得到flag:flag{d9-dE6-20c}
[SUCTF2019]SignIn
这是个RSA,我不理解为什么要出这个。。。
flag:flag{Pwn_@_hundred_years}
[MRCTF2020]Transform
打开得到:
写出脚本:
#include <iostream>
using namespace std;
int main()
{
int ans[99] = {103, 121, 123, 127, 117, 43, 60, 82, 83, 121,
87, 94, 93, 66, 123, 45, 42, 102, 66, 126,
76, 87, 121, 65, 107, 126, 101, 60, 92, 69,
111, 98, 77};
int key[99] = {9,10,15,23,7,24,12,6,1,16,3,17,32,29,11,30,27,22,4,13,19,20,21,2,25,5,31,8,18,26,28,14};
int flag[99];
int i;
for(i = 0; i <= 32; i++)
{
ans[i] ^= key[i];
flag[key[i]] = ans[i];
}
for(i = 0; i <= 32; i++)
{
cout << char(flag[i]);
}
return 0;
}
得到flag:flag{Tr4nsp0sltiON_Clph3r_1s_3z}
[WUSTCTF2020]level2
有壳,但是可以upx -d,解决后进去即可得到flag:flag{Just_upx_-d}
[ACTF新生赛2020]usualCrypt
进去后可以分析出主加密函数在sub_401080
进去后很开心是个base64,直接解密得到乱码,观察发现函数开始和结尾分别有这两个诡异的东西:
一个更改密码表,一个更改结果,给它推回去:
#include <iostream>
using namespace std;
int main()
{
char key[99] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char ans[99] = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9";
int i, tmp;
for(i = 6; i < 15; i++)
{
tmp = key[i + 10];
key[i + 10] = key[i];
key[i] = tmp;
}
for(i = 0; i <= 35; i++)
{
if(ans[i] >= 'a' && ans[i] <= 'z')
{
ans[i] -= 32;
}
else
{
if(ans[i] >= 'A' && ans[i] <= 'Z')
{
ans[i] += 32;
}
}
}
for(i = 0; i <= 63; i++)
{
cout << key[i];
}
cout << endl;
for(i = 0; i <= 35; i++)
{
cout << ans[i];
}
return 0;
}
得到新的密码表:ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/
旧结果:ZmxhZ3tiGNXlXjHfaDTzN2FfK3LycRTpc2L9
拿着这两个东西解密得到flag:flag{bAse64_h2s_a_Surprise}
[HDCTF2019]Maze
有壳但是可以upx -d:
进去发现有一个花指令,给它nop掉:
正常编译后得到:
在跟进dword_408078和dword_40807C时顺带找出地图:
由起始坐标(7,0)和结束坐标(5,-4)在根据+和F的位置推出地图长这样:
*******+**
*******s**
****ssss**
**sss*****
**s**F****
**ssss****
**********
走一遍得到flag:flag{ssaaasaassdddw}
[MRCTF2020]Xor
进去F5发现IDA会报个错,跟进提示错误的函数先把它反编译出来,在回来反编译主函数就可以了。应该是IDA遇见了一个它不认识的东西,让他先认识一下就行了:
写个代码:
#include <iostream>
using namespace std;
int main()
{
int ans[99] = {77, 83, 65, 87, 66, 126, 70, 88, 90, 58,
74, 58, 96, 116, 81, 74, 34, 78, 64, 32,
98, 112, 100, 100, 125, 56, 103};
int i;
for(i = 0; i <= 26; i++)
{
ans[i] ^= i;
cout << char(ans[i]);
}
return 0;
}
得到flag:flag{@_R3@1ly_E2_R3verse!}
标签:逆向,BUUCTF,int,99,flag,key,第一页,include,IDA From: https://www.cnblogs.com/Clovershrub/p/16907675.html