XCTF-RE

前言

博客已经搭了有几周了,但是由于最近考试真的让我压力很大(对于菜鸡的我来说复习真的不是一件容易的事)

不想复习的我,来水水博客放松一下吧!

不说了直接暴力上题!

0x01.open-source

首先当然是下载附件啦!

一看是一个.c文件,啥也别说直接用sublime打开

第一次上传WP到自己的网站有点小小的激动!

自我感觉这题好像跟逆向没有啥关系,让我们简单来分析一下吧!

大概浏览一遍,发现hash貌似就是我们想要的flag,所以我们需要找到first,second和 strlen(argv[3]) 三个参数

unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207;

直接来看第8行,其中atoi函数,是把字符串转为数字,如atoi(“123”)就是数字123, 所以 0xcafe 即:51966

unsigned int first = atoi(argv[1]);
if (first != 0xcafe) {
printf("you are wrong, sorry.\n");
exit(2);
}

再来看第13行,参数对5取余不能等于3,且对17取余等于8,发现自然数25就可以

unsigned int second = atoi(argv[2]);
if (second % 5 == 3 || second % 17 != 8) {
printf("ha, you won't get it!\n");
exit(3);
}

最后一个参数即argv[3]=h4cky0u!

if (strcmp("h4cky0u", argv[3])) {
printf("so close, dude!\n");
exit(4);
}

直接把三个参数的值改到程序上去

first = 0xcafe , (second%17)= 8 ,strlen(argv[3]) = strlen("h4cky0u")

现在我们编写简单脚本

#include <stdio.h>
#include <string.h>

int main() {

unsigned int hash = 0xcafe * 31337 + 8 * 11 + strlen("h4cky0u") - 1615810207;

printf("Get your key: ");

printf("%x\n", hash);

return 0;
}

得到flag!!!

0x02.simple-unpack

题目描述:菜鸡拿到了一个被加壳的二进制文件

由于菜鸡本人对kali虚拟机并不是很会用,所以只能先拖入winhex里碰碰运气看看是什么壳!

尝试在winhex查找中输入flag

运气真好,把括号里的乱码删掉即为 flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}

0x03.logmein

这道题终于涉及到了逆向ida静态分析,让我们把它拖入ida64(提前在exeinfope查看其为64位文件),并佛系按下F5

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
size_t v3; // rsi
int i; // [rsp+3Ch] [rbp-54h]
char s[36]; // [rsp+40h] [rbp-50h]
int v6; // [rsp+64h] [rbp-2Ch]
__int64 v7; // [rsp+68h] [rbp-28h]
char v8[8]; // [rsp+70h] [rbp-20h]
int v9; // [rsp+8Ch] [rbp-4h]

v9 = 0;
strcpy(v8, ":\"AL_RT^L*.?+6/46");
v7 = 28537194573619560LL;
v6 = 7;
printf("Welcome to the RC3 secure password guesser.\n", a2, a3);
printf("To continue, you must enter the correct password.\n");
printf("Enter your guess: ");
__isoc99_scanf("%32s", s);
v3 = strlen(s);
if ( v3 < strlen(v8) )
sub_4007C0(v8);
for ( i = 0; i < strlen(s); ++i )
{
if ( i >= strlen(v8) )
((void (*)(void))sub_4007C0)();
if ( s[i] != (char)(*((_BYTE *)&v7 + i % v6) ^ v8[i]) )
((void (*)(void))sub_4007C0)();
}
sub_4007F0();
}

仔细分析一下代码,发现这个for循环是找出flag的关键,写一个c++文件试一试吧

#include <iostream>
#include <stdio.h>
using namespace std;

int main()
{
long long a = 28537194573619560; //让v7=a
char * p = (char*)&a; //(char *)将int型指针(指向4个字节)转换成char型指针(指向一个字节)
char b[] = ":\"AL_RT^L*.?+6/46"; //使char b[]=v7
for(int i = 0;b[i]!=0;i++){ //for循环执行
b[i] = b[i]^p[i%7];
}
cout<<b<<endl;

输出就得到flag啦! flag{RC3-2016-XORISGUD}

0x04.insanity

巨巨弱觉得前面的题目太难了,来个简单的缓一下

拖入ida中直接暴力F5,好像也没啥关键信息啊,这时候就要用到ida的各种快捷键了。

shift+F12看一看strings window中有没有什么有效信息

直接发现flag 9447{This_is_a_flag}

0x05.python-trade

下载附件发现是pyc文件,利用python反编译工具 在线工具

得到代码如下:

import base64

def encode(message):
s = ''
for i in message:
x = ord(i) ^ 32
x = x + 16
s += chr(x)

return base64.b64encode(s)

correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt'
flag = ''
print 'Input flag:'
flag = raw_input()
if encode(flag) == correct:
print 'correct'
else:
print 'wrong'

反编译的意思大概就是反着来呗!

如上代码运用for循环进行异或和加法操作最终得到base64字符串

那我们就将base64字符串在for循环里进行减法和异或操作不就得到flag了嘛?

简单脚本如下:

import base64

buf = base64.b64decode('XlNkVmtUI1MgXWBZXCFeKY+AaXNt') //利用python语法讲base64码直接转,再也不用借助工具啦
flag = ''
for i in buf:
i =i-16
i =i^32
flag =flag+chr(i)

print(flag)

嘻嘻嘻得到flag nctf{d3c0mpil1n9_PyC}

0x06.game

直接拖入ida中,恶心人的是我没有在这道题中发现main函数,导致我无法运用万能快捷键F5

这让我如何是好,不管了shift+F12试一试

哇!我真幸运

发现了done!!! the flag is我就感觉这里一定有flag

鼠标点击flag 然后跳转到这一行

鼠标右键点击 List cross references to 并按下F5 (这一步说实话菜鸡也不太懂,于是参考了别人的博客)

终于找到了原代码!!!

sub_45A7BE("done!!! the flag is ");
v59 = 18;
v60 = 64;
v61 = 98;
v62 = 5;
v63 = 2;
v64 = 4;
v65 = 6;
v66 = 3;
v67 = 6;
v68 = 48;
v69 = 49;
v70 = 65;
v71 = 32;
v72 = 12;
v73 = 48;
v74 = 65;
v75 = 31;
v76 = 78;
v77 = 62;
v78 = 32;
v79 = 49;
v80 = 32;
v81 = 1;
v82 = 57;
v83 = 96;
v84 = 3;
v85 = 21;
v86 = 9;
v87 = 4;
v88 = 62;
v89 = 3;
v90 = 5;
v91 = 4;
v92 = 1;
v93 = 2;
v94 = 3;
v95 = 44;
v96 = 65;
v97 = 78;
v98 = 32;
v99 = 16;
v100 = 97;
v101 = 54;
v102 = 16;
v103 = 44;
v104 = 52;
v105 = 32;
v106 = 64;
v107 = 89;
v108 = 45;
v109 = 32;
v110 = 65;
v111 = 15;
v112 = 34;
v113 = 18;
v114 = 16;
v115 = 0;
v2 = 123;
v3 = 32;
v4 = 18;
v5 = 98;
v6 = 119;
v7 = 108;
v8 = 65;
v9 = 41;
v10 = 124;
v11 = 80;
v12 = 125;
v13 = 38;
v14 = 124;
v15 = 111;
v16 = 74;
v17 = 49;
v18 = 83;
v19 = 108;
v20 = 94;
v21 = 108;
v22 = 84;
v23 = 6;
v24 = 96;
v25 = 83;
v26 = 44;
v27 = 121;
v28 = 104;
v29 = 110;
v30 = 32;
v31 = 95;
v32 = 117;
v33 = 101;
v34 = 99;
v35 = 123;
v36 = 127;
v37 = 119;
v38 = 96;
v39 = 48;
v40 = 107;
v41 = 71;
v42 = 92;
v43 = 29;
v44 = 81;
v45 = 107;
v46 = 90;
v47 = 85;
v48 = 64;
v49 = 12;
v50 = 43;
v51 = 76;
v52 = 86;
v53 = 13;
v54 = 114;
v55 = 1;
v56 = 117;
v57 = 126;
v58 = 0;
for ( i = 0; i < 56; ++i )
{
*(&v2 + i) ^= *(&v59 + i);
*(&v2 + i) ^= 0x13u;
}
return sub_45A7BE("%s\n");

上边代码是求flag的过程,大概意思是它将程序分为了两个数组,一组为v2到v58另一组为v59~v115

将第一个数组与第二个数组异或再将值赋予第一个数组,然后第一个数组再和0x13异或,最后把第一个数组转化为字符串即为flag

思路既然懂了,那我们直接上代码:

a=[18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
b=[123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
i=0
c=''
while (i<56):
a[i]^=b[i]
a[i]^=19
c=c+chr(a[i])
i=i+1
print(c)

得到flag zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}