攻防世界 REVERSE 新手区/getit
下载得到附件,拖入Exeinfo PE中查一下壳
用IDA64bit打开,找到main函数按f5查看伪代码
下面开始分析代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
__int64 v5; // [rsp+0h] [rbp-40h]
int i; // [rsp+4h] [rbp-3Ch]
FILE *stream; // [rsp+8h] [rbp-38h]
char filename[8]; // [rsp+10h] [rbp-30h]
unsigned __int64 v9; // [rsp+28h] [rbp-18h]
v9 = __readfsqword(0x28u);
LODWORD(v5) = 0;
while ( (signed int)v5 < strlen(s) )
{
if ( v5 & 1 )
v3 = 1;
else
v3 = -1;
*(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
LODWORD(v5) = v5 + 1;
}
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u, v5);
for ( i = 0; i < strlen(&t); ++i )
{
fseek(stream, p[i], 0);
fputc(*(&t + p[i]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fclose(stream);
remove(filename);
return 0;
}
这一段是定义一个变量v5=0,然后while循环将s加到t偏移地址为10的后面,然后再加v3
LODWORD(v5) = 0;
while ( (signed int)v5 < strlen(s) )
{
if ( v5 & 1 )
v3 = 1;
else
v3 = -1;
*(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
LODWORD(v5) = v5 + 1;
}
查看s和t的字符串,s=c61b68366edeb7bdce3c6820314b7498
t = harifCTF{???} 看来t就是输出的flag了
strcpy(filename, "/tmp/flag.txt");
stream = fopen(filename, "w");
fprintf(stream, "%s\n", u, v5);
这里是进行文件操作,先将flag.txt复制给filename,然后以写方式打开filename, stream为fopen()函数的返回值,如果打开失败则返回NULL,
fopen()的函数原型为:FILE *fopen(char *filename, *type);
type的形式参数类型:
“r” 打开文字文件只读
“w” 打开只写,如果不存在则新建,如果存在则清空
“a” 增补, 如果文件不存在则创建一个
“r+” 打开一个文字文件读/写
“w+” 创建一个文字文件读/写
“a+” 打开或创建一个文件增补
“b” 二进制文件(可以和上面每一项合用)
“t” 文这文件(默认项)
fprintf()为标准输出函数,用于按指定格式向文件写数据,
函数原型为: int fprintf(FILE *fp ,conse char *format,…),
这里是输出一排星号,可以不用管
for ( i = 0; i < strlen(&t); ++i )
{
fseek(stream, p[i], 0);
fputc(*(&t + p[i]), stream);
fseek(stream, 0LL, 0);
fprintf(stream, "%s\n", u);
}
fseek()的函数原型int fseek(FILE *stream, long offset, int fromwhere);
函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
fput()的函数原型为:int fputs(const char *s,FILE *p),向文件指针p的位置写入一个字符
这里将文件指针指向离文件头偏移p[i]的位置,然后将t偏移p[i]的字符输入。其实就是输出的顺序不一样而已,比如我要输出123,我可以先输出2,然后在2的左边输出1,在2的右边输出3,和我直接输出123的结果是一样的。
这里是p[]的值,为16进制的数组,每隔3个0是一个16进制
知道了算法就可以编写脚本来解码了
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main()
{
char s[] = "c61b68366edeb7bdce3c6820314b7498";
int p[] = {0x18,0x19,0x20,0x28,0x24,0x1C,0x11,0x22,0x27,0x10,0x21,0x13,0x1A,5,3,0x1D,0x1B,0x1F,4,8,0x0F,0x25,0x2A,0x0E,0x29,2,0x17,0x15,0,0x0A,0x14,7,0x0B,1,0x0D,6,0x26,0x12,0x23,0x0C,0x16,9};
char t[] = "harifCTF{????????????????????????????????}";
int v5 = 0;
int v3;
while(v5 < strlen(s))
{
if(v5 & 1)
v3 = 1;
else
v3 = -1;
t[v5 + 10] = s[v5] + v3;
v5 ++;
}
for ( int i = 0; i < strlen(t) ; i++)
{
printf("%c",t[i]);
}
return 0;
}
然后输出结果为
这不对呀,倒回去看下,这里确实是t之后偏移10啊
*(&t + (signed int)v5 + 10) = s[(signed int)v5] + v3;
然后我看了下t的值
然后发现在t后面还有一个 db 53h 转字符后刚好是字符S
将S加到t前面,输出结果,得到flag:SharifCTF{b70c59275fcfa8aebf2d5911223c6589}
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main()
{
char s[] = "c61b68366edeb7bdce3c6820314b7498";
int p[] = {0x18,0x19,0x20,0x28,0x24,0x1C,0x11,0x22,0x27,0x10,0x21,0x13,0x1A,5,3,0x1D,0x1B,0x1F,4,8,0x0F,0x25,0x2A,0x0E,0x29,2,0x17,0x15,0,0x0A,0x14,7,0x0B,1,0x0D,6,0x26,0x12,0x23,0x0C,0x16,9};
char t[] = "SharifCTF{????????????????????????????????}";
int v5 = 0;
int v3;
while(v5 < strlen(s))
{
if(v5 & 1)
v3 = 1;
else
v3 = -1;
t[v5 + 10] = s[v5] + v3;
v5 ++;
}
for ( int i = 0; i < strlen(t) ; i++)
{
printf("%c",t[i]);
}
return 0;
}