学破解第139天,《攻防世界reverse练习区666》学习
前言:
从小学到大专(计算机网络技术专业),玩过去的,所以学习成绩惨不忍睹,什么证书也没考,直到找不到工作才后悔,不知道怎么办才好。
2017年12月16日,通过19元注册码注册论坛账号,开始做伸手党,潜水一年多,上来就是找软件。(拿论坛高大上的软件出去装X)
2018年8月10日,报名了华中科技大学网络教育本科(计算机科学与技术专业)2018级秋季。(开始提升学历)
2019年6月17日,不愿再做小菜鸟一枚,开始零基础学习破解。(感谢小糊涂虫大哥在我刚开始学习脱壳时,录制视频解答我的问题)
2020年7月7日,感谢H大对我的鼓励,拥有了第一篇获得优秀的文章。(接下来希望学习逆向,逆天改命)
2021年8月11日,华科学位英语2次不过,仅取得了毕业证书,学业提升失败,开始琢磨考注册类和职称类证书,谋求涨薪
坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1278021-1-1.html
立帖为证!--------记录学习的点点滴滴
0x1下载文件
1.下载CM,是一个压缩包,解压后发现并不是exe文件。
2.通过exeinfo软件查壳,发现是64位ELF文件,如图所示:
3.不会Linux操作,这就没法动态调试了,用IDA静态分析看看,毕竟只是1分题,应该难度不大。
0x2代码分析
1.使用64位IDA程序打开,这是main函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[240]; // [rsp+0h] [rbp-1E0h] BYREF
char v5[240]; // [rsp+F0h] [rbp-F0h] BYREF
memset(s, 0, 0x1EuLL);
printf("Please Input Key: ");
__isoc99_scanf("%s", v5);
encode(v5, (__int64)s);
if ( strlen(v5) == key )
{
if ( !strcmp(s, enflag) )
puts("You are Right");
else
puts("flag{This_1s_f4cker_flag}");
}
return 0;
}
可以看到我输入v5,然后调用encode函数得到处理后的s,和enflag相等就是正确的。
2.那么我们看看encode函数:
int __fastcall encode(const char *a1, __int64 a2)
{
char v3[104]; // [rsp+10h] [rbp-70h]
int v4; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]
i = 0;
v4 = 0;
if ( strlen(a1) != key )
return puts("Your Length is Wrong");
for ( i = 0; i < key; i += 3 )
{
v3[i + 64] = key ^ (a1[i] + 6);
v3[i + 33] = (a1[i + 1] - 6) ^ key;
v3[i + 2] = a1[i + 2] ^ 6 ^ key;
*(_BYTE *)(a2 + i) = v3[i + 64];
*(_BYTE *)(a2 + i + 1LL) = v3[i + 33];
*(_BYTE *)(a2 + i + 2LL) = v3[i + 2];
}
return a2;
}
打开数据段看一下,key是什么,key的长度是什么,一目了然。
.data:0000000000004060 enflag db 'izwhroz""w"v.K".Ni',0
.data:0000000000004060 ; DATA XREF: main+8F↑o
.data:0000000000004073 align 20h
.data:0000000000004080 public key
.data:0000000000004080 key dd 12h ; DATA XREF: encode+2D↑r
.data:0000000000004080 ; encode+5F↑r ...
.data:0000000000004080 _data ends
3.把处理v5的算法手动优化一下成:
for ( i = 0; i < flag; i += 3 )
{
flag[i] = key ^ (a1[i] + 6);
flag[i + 1] = (a1[i + 1] - 6) ^ key;
flag[i + 2] = a1[i + 2] ^ 6 ^ key;
}
现在就是一个数学代数问题了,已知a,x,a=b+x,求b的值。
4.现在就是带入已知的值,求未知的值,a=b+x,可以变成b=a-x,用代码表示就是:
for (i = 0; i < key; i += 3)
{
(a1[i] + 6) = flag[i] ^ key;
(a1[i + 1] - 6)= flag[i + 1] ^ key;
a1[i + 2] ^ 6 = flag[i + 2] ^ key;
}
继续化简,我用arr数组代替a1,看着舒服点:
for (i = 0; i < key; i += 3)
{
arr[i] = flag[i] ^ key - 6;
a1[i + 1] = flag[i + 1] ^ key + 6;
a1[i + 2] = flag[i + 2] ^ key ^ 6;
} for (i = 0; i < key; i += 3)
5.解密算法已经反推出来了,接下来写程序爆破吧,完整代码如下:
#include <iostream>
using namespace std;
int main()
{
char flag[19] = "izwhroz\"\"w\"v.K\".Ni";
char arr[19] = "";
for (int i = 0; i < 18; i += 3)
{
arr[i] = (flag[i] ^ 18) - 6;//避免因为运算符优先级导致结果不对,我加了小括号
arr[i + 1] = (flag[i + 1] ^ 18) + 6;
arr[i + 2] = (flag[i + 2] ^ 18) ^ 6;
}
arr[18] = '\0';
cout << arr << endl;
system("pause");
}
6.编译运行结果如下:
unctf{b66_6b6_66b}
请按任意键继续. . .
7.输入flag进行验证:
0x3总结
1.IDA F5功能太强大,直接把源码反编译出来了。
2.运用逆向思维和数学逻辑,不用理解算法,直接恒等式变换,把结果作为输入,推出flag。
3.总体来说,本题比较简单,适合我这样的菜鸟练手。
0x4参考资料
1.无
PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!