前言:
坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1582287-1-1.html
立帖为证!--------记录学习的点点滴滴
0x1 锁定目标
1.百度攻防世界:Reversing-x64Elf-100,1分题,应该没有难度吧
2.老规矩,先查壳
3.手上没有linux系统,但是简单的题应该用不上动态调试,靠IDA足够了。
0x2 静态分析
1.直接拖进IDA看看main函数,可以看到sub_4006FD函数是关键,它的返回值决定我们输入的flag是否正确:
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 result; // rax
char s[264]; // [rsp+0h] [rbp-110h] BYREF
unsigned __int64 v5; // [rsp+108h] [rbp-8h]
v5 = __readfsqword(0x28u);
printf("Enter the password: ");
if ( !fgets(s, 255, stdin) )
return 0LL;
if ( (unsigned int)sub_4006FD((__int64)s) )
{
puts("Incorrect password!");
result = 1LL;
}
else
{
puts("Nice!");
result = 0LL;
}
return result;
}
2.再去看看sub_4006FD函数,通过main函数if条件我们知道这里必须返回true,也就是1:
__int64 __fastcall sub_4006FD(__int64 a1)
{
int i; // [rsp+14h] [rbp-24h]
__int64 v3[4]; // [rsp+18h] [rbp-20h]
v3[0] = (__int64)"Dufhbmf";
v3[1] = (__int64)"pG`imos";
v3[2] = (__int64)"ewUglpt";
for ( i = 0; i <= 11; ++i )
{
if ( *(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) != 1 )
return 1LL;
}
return 0LL;
}
3.有点懵,if只要成立一次就返回1???那我怎么知道完整的flag计算流程!!!
4.vs 2015社区版一直自动退出,登录也登不上去,这下直接把代码拷贝过去运行的方法也没了。
5.人工计算,大脑里运行一下,并记录结果:
for循环:
1)v3[0] + 0 - a1[0]!=1
2)v3[1] + 0 - a1[1]!=1
3)v3[2] + 0 - a1[2]!=1
==================================
1)v3[0] + 2 - a1[3]!=1
2)v3[1] + 2 - a1[4]!=1
3)v3[2] + 2 - a1[5]!=1
==================================
1)v3[0] + 4 - a1[6]!=1
2)v3[1] + 4 - a1[7]!=1
3)v3[2] + 4 - a1[8]!=1
==================================
1)v3[0] + 6 - a1[9]!=1
2)v3[1] + 6 - a1[10]!=1
3)v3[2] + 6 - a1[11]!=1
6.共循环11次,最后结束循环,最终就是字符串Dpef'ubmlfst减去我们输入的字符串a1的值判断是否不等于1,如果不等于1,就返回1,也就是true。
7.最后依靠百度,终于整明白了......,据说linux环境下函数执行成功返回0代表正确,非0代表错误,不知道对不对,但是这样理解这个代码就能看懂了。
8.那么只要让每次if比较结果为真,也就是两个字符串相减等于1,最后循环结束后,返回0,代表true,成功。
9.v3 -flag =1 ,代换过来就是flag = v3 - 1所以flag就是Dpef'ubmlfst - 1。
0x3 写脚本
1.这里我就不查表的一个个自己算了,你看看那个循环,算了老半天,不过收获,就是能看到那一行代码的意思了。
2.看懂代码了,写脚本就好说,以前这种我就是复制到c++ ide工具里,颠倒一下计算过程赋值语句,不用看懂算法代码,跑一下就能得到flag。
3.打开eclipse,编写java脚本:
1)因为java没有指针,但是学c语言的时候知道,数组就是指针
2)指针取值,这里用数组取值即可
3)字符串可以看做是一个char数组
4.完整的代码:
package ctf;
public class test01 {
public static void main(String[] args) {
int i;
//定义一个二维字符数组,把v3字符化
char[][] v3 = new char[][] {{'D','u','f','h','b','m','f'},{'p','G','`','i','m','o','s'},{'e','w','U','g','l','p','t'}};
StringBuffer flag = new StringBuffer("");
for ( i = 0; i <= 11; ++i )
{
flag.append((char) (v3[i % 3][2 * (i / 3)] - 1)) ;//强制转换char类型,追加到字符串中
}
System.out.println("flag:"+ flag);
}
}
输出:flag:Code_Talkers
5.去验证一下,输入flag,成功截图:
0x4 总结
1.函数返回值那里把我给整懵了,浪费了不少的时间。
2.vs2015社区版不知道啥原因,一打开就提示要登录,登录不上去,秒退,要不然这代码直接粘过去,都不用分析if里面那一行代码就能直接爆出flag。