BUUCTF逆向工程第二页部分题目
[MRCTF2020]hello_world_go
代码写得根本看不懂在干什么,但是瞎点一通发现unk_4D3C58里就是flag:flag{hello_world_gogogo}
从结果来看应该是一个go语言,无语。。。
[WUSTCTF2020]level3
打开看见它想让我破译一个base64:
点进加密函数可以跟踪到密码表:
用这个密码表解码发现解出来是乱码......想到密码表可能被修改过,查看它的交叉引用:
写个简单的脚本得到flag:flag{Base64_is_the_start_of_reverse}
[GWCTF 2019]xxor
打开看见:
前面一段对输入进行TEA,之后判断结果,解码脚本在此:
#include <stdio.h>
#include <stdint.h>
void decrypt (int *v, int *k)
{
unsigned int v0 = v[0], v1 = v[1], i;
int delta = 1166789954;
int sum = 0;
for(i = 0; i < 64; i++)
{
sum += delta;
}
for (i = 0; i < 64; i++)
{
v1 -= (v0 + sum + 20) ^ ((v0 << 6) + k[2]) ^ ((v0 >> 9) + k[3]) ^ 0x10;
v0 -= (v1 + sum + 11) ^ ((v1 << 6) + k[0]) ^ ((v1 >> 9) + k[1]) ^ 0x20;
sum -= delta;
}
v[0] = v0;
v[1] = v1;
return;
}
int main()
{
int v[2] = {}, k[4] = {2,2,3,4};
unsigned int a1[6] = {-548868226, 550153460, 3774025685, 1548802262, 2652626477, -2064448480};
int i, j;
for(i = 0; i <= 2; i++)
{
v[0] = a1[i*2];
v[1] = a1[i*2+1];
decrypt(v, k);
a1[i*2] = v[0];
a1[i*2+1] = v[1];
}
for(i = 0; i <= 5; i++)
{
for(j = 2; j >= 0; j--)
{
printf("%c", *((char *)&a1[i] + j));
}
}
return 0;
}
得到flag:flag{re_is_great!}
说实话,写完这题我仍然不是很理解HIDWORD、LODWORD和ELF的逆序存储,全靠IDA动调测算出数据的存储方式,然后进行逆推,再根据输出调整顺序。。。
虽说篇幅不长,但是这个b干了我将近4个小时
[FlareOn4]IgniteMe
打开IDA,果然,C++写出来的程序最恶心了(虽然我喜欢用C++):
sub_4010F0是输入函数,sub_401050是加密函数:
其中sub401000函数里面是一个__ROL4__函数,百度了半天我也没看明白,但是IDA动调之后可以看见最后v4=4,所以也可以写出脚本:
#include <iostream>
using namespace std;
int main()
{
int ans[99] = {13, 38, 73, 69, 42, 23, 120, 68, 43, 108,
93, 94, 69, 18, 47, 23, 43, 68, 111, 110,
86, 9, 95, 69, 71, 115, 38, 10, 13, 19,
23, 72, 66, 1, 64, 77, 12, 2, 105};
int flag[99];
int i;
int v4 = 4;
for(i = 38; i >= 0; i--)
{
flag[i] = v4 ^ ans[i];
v4 = flag[i];
}
for(i = 0; i <= 38; i++)
{
cout << char(flag[i]);
}
return 0;
}
得出flag:flag{[email protected]}
[WUSTCTF2020]Cr0ssfun
没啥技术含量
flag:flag{cpp_@nd_r3verse_@re_fun}
[FlareOn6]Overlong
IDA中代码很短,理论上运行一遍就有答案:
其中unk_402008是给定的175空间的数组,但是sub_401160中对于次数组的调用最多只有28*4=112空间,因此推测所传参数28太小,所以拖入x32dbg修改对应二进制值1C为AE:
之后运行起来,即可得到结果:
得到flag:flag{[email protected]}
[UTCTF2020]basic-re
shift+F12:
得到flag:flag{str1ngs_1s_y0ur_fr13nd}
[FlareOn3]Challenge1
简单的变表base64,得到flag:flag{[email protected]}
[ACTF新生赛2020]Oruga
这是一道比较抽象的迷宫题:
由这个可以推出地图是一个16*16的空间,长这个样子:
看一看它的校验部分:
它的v2在校验中就进行了更改,而下一次循环又不会对v2进行回溯,因此它走迷宫的路线会变成直来直去的样子。一直向某个方向走到底直到遇见非空的格子,同时还不能越界,因此路线为:
得到flag:flag{MEWEMEWJMEWJM}
特殊的 BASE64
简单的变表base64,不得不说,C++的逆向代码看起来确实恶心
得到flag:flag{Special_Base64_By_Lich}
[Zer0pts2020]easy strcmp
主函数内只有这些,提交发现这不是正确答案:
返回去看看init函数有没有进行一些什么操作:
发现它其实调用了一些函数,只不过是通过直接访问地址的形式调用的,双击funcs_889可以看到:
它调用了两个函数sub_6E0和函数sub_795,其中第一个没什么卵用,跟进第二个:
发现这个函数很神奇,将strcmp函数的地址传给了qword_201090,将sub_6EA函数的地址传给了off_201028,双击sub_6EA查看:
发现sub_6EA对参数做了一通操作,然后返回地址在qword_201090的函数的值,而这个函数恰好就是刚赋完值的strcmp函数。在sub_795函数里将sub_6EA函数的地址传给了off_201028,双击off_201028查看:
发现off_201028地址上的函数恰好又是strcmp函数。所以主函数里执行strcmp时其实先执行了sub_6EA函数,再执行strcmp函数,可以写出脚本:
#include <iostream>
using namespace std;
int main()
{
char p[99] = "zer0pts{********CENSORED********}";
long long k[4] = {0, 0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B};
for (int i = 0; i < 4; i++)
{
*(long long *)&(p[i * 8]) += k[i];
}
cout << p;
}
得到flag:flag{l3ts_m4k3_4_DETOUR_t0d4y}
[ACTF新生赛2020]Universe_final_answer
是个简单的z3,此题大多数时间用在了z3的安装和调查使用教程,算出key的值之后用IDA动调一下即可:
得到flag:flag{F0uRTy_7w@_42}
[WUSTCTF2020]level4
这是个算法题,给出二叉树的中序遍历和后序遍历,求先序遍历。有一点神奇的是在IDA里静态或者动调的时候都没有找到它存放这些数据的地方......
得到flag:flag{This_IS_A_7reE}
findKey
又一个非常恶心的C++,主函数东西很少,shift+F12找到关键词“flag{}”,双击跟进发现花指令,nop掉:
之后进入真正恶心的地方,关注函数sub_40101E:
和sub_401005
sub_40101E进去发现:
0x8003u是MD5加密的特征值,因此判定整个函数用于MD5。
对于第一个sub_401005,就是将那一长串绿色的东西每一位异或‘S’,得到的东西应该为MD5之后的输入,在线解密得到123321。而第二个sub_401005并没有找到v5-492对应的值,猜测就是输入,结果证明我猜对了。附上解密脚本
#include <iostream>
using namespace std;
int main()
{
int key[99] = {87, 94, 82, 84, 73, 95, 1, 109, 105, 70, 2, 110, 95, 2, 108, 87, 91, 84, 76};
char ans[99] = "0kk`d1a`55k222k2a776jbfgd`06cjjb";
int i;
for(i = 0; i <= 31; i++)
{
ans[i] ^= 'S';
cout << char(ans[i]);
}
cout << endl;
char k[9] = "123321";
for(i = 0; i <= 18; i++)
{
key[i] ^= k[i % 6];
cout << char(key[i]);
}
return 0;
}
得到flag:flag{n0_Zu0_n0_die}
确实,no zuo no die,没事别碰逆向,这个b又干了我4个小时。
[羊城杯 2020]easyre
这个没啥,就是繁,encodeone进行base64,encodetwo乾坤大挪移,encodethree凯撒,逆过来就行
得到flag:flag{672cc4778a38e80cb362987341133ea2}
[FlareOn5]Minesweeper Championship Registration
是个java的程序,没逆过,但是拖进IDA就能得到flag:flag{[email protected]}
[ACTF新生赛2020]SoulLike
一起来感受3000行屎山代码的美,没有含金量,flag:flag{b0Nf|Re_LiT!}
[FlareOn5]Ultimate Minesweeper
get了一个dnSpy的新玩法。拖进去容易找到加密函数:
但是仔细看一看发现它用revealedCells作为种子生成了一个随机数数组array,之后在加密输出。因此想法是动调,查看一下会让我们失败的函数:
根据英文提示,第一个if就是失败判定,把它右键、编辑方法,给它注释掉:
右下角编译之后Ctrl+shift+s保存为新程序,运行新程序,找到三个非雷地块:
之后再在正常的程序里点击这三个地块,得到flag:flag{[email protected]}
[FlareOn1]Bob Doge
又是一个C#的程序,拖入dnSpy,容易找到加密函数:
发现需要寻找dat_secret,可惜找不到(话说,这玩意儿是怎么藏起来的?),所以准备动调:
在数据栏中得到flag:flag{[email protected]}
[CFI-CTF 2018]IntroToPE
这道题就比较水了,打开找到判断函数:
可以看出,应当使validatePassword.verifyPassword()返回真值,双击跟踪:
看见是一个base64,理论上应该接着去找加密使用的对应表,可惜没找到,就用默认的吧。
得到flag:flag{.NetC#_1s_@w3s0m3}