2022-1-16
reverse2
扔到IDA64里解析, F5生成伪代码
通过分析得出经过一定的变换后与flag进行比较的
查看flag的值,是{hacking_for_fun} 再返回前面看如何对flag进行变换的,将105、114、49转换成值,
箭头所指的函数功能为,把flag中存在的’i’以及’r’转换成’1’,进而得出正确flag。
2022-1-17
内涵的软件
下载好以后发现是乱码的exe文件,拖到ExeinfoPE里查看信息,
可以看到跳转到main0函数里 打开main0函数 F5看伪代码,
看到一串字符串,直接尝试,就是了,不得不吐槽一下,这字符串我以为还是加密的呢,然而并不是。
2022-1-18
新年快乐
先放到ExeinfoPE里查看
发现是加壳的
使用脱壳工具脱一下壳
代码逻辑如图,比对str1和str2,str2的值直接就给了。就是"HappyNewYear!"。
2022-1-19
XOR
下载下来是个无后缀文件,扔到IDA64里解析,看到main函数,直接F5, 看到是对_b跟global做对比,
所以看一下global什么内容,跟进是字符串。
写一个python脚本
s = ['f',0xA,'k',0xC,'w&O.@',0x11,'x',0xD,'Z;U',0x11,'p',0x19,'F',0x1F,'v"M#D',0xE,'g',6,'h',0xF,'G2O',0]
for i in range(1,len(s)):
if(isinstance(s[i],int)): #如果为int类型,转换为char类型
s[i]=chr(s[i])
s = ''.join(s) #将列表拼接成字符串
flag = 'f' #flag的第一位不进行异或,所以直接写为f
for i in range(1,len(s)):
flag += chr(ord(s[i])^ord(s[i-1])) #异或操作,两次异或会还原
print(flag)
2022-1-20
reverse3
下载下来是reverse_3.exe,扔到ExeinfoPE里,没加壳,扔到IDA里,看见了main0,直接F5,
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
size_t v3; // eax
const char *v4; // eax
size_t v5; // eax
char v7; // [esp+0h] [ebp-188h]
char v8; // [esp+0h] [ebp-188h]
signed int j; // [esp+DCh] [ebp-ACh]
int i; // [esp+E8h] [ebp-A0h]
signed int v11; // [esp+E8h] [ebp-A0h]
char Destination[108]; // [esp+F4h] [ebp-94h] BYREF
char Str[28]; // [esp+160h] [ebp-28h] BYREF
char v14[8]; // [esp+17Ch] [ebp-Ch] BYREF
for ( i = 0; i < 100; ++i )
{
if ( (unsigned int)i >= 0x64 )
j____report_rangecheckfailure();
Destination[i] = 0;
}
sub_41132F("please enter the flag:", v7);
sub_411375("%20s", (char)Str);
v3 = j_strlen(Str);
v4 = (const char *)sub_4110BE(Str, v3, v14);
strncpy(Destination, v4, 0x28u);
v11 = j_strlen(Destination);
for ( j = 0; j < v11; ++j )
Destination[j] += j;
v5 = j_strlen(Destination);
if ( !strncmp(Destination, Str2, v5) )
sub_41132F("rigth flag!\n", v8);
else
sub_41132F("wrong flag!\n", v8);
return 0;
}
看出来是输入一个字符串然后经过sub_4110BE函数进行加密,然后再通过一个for循环进行变换,然后与str2进行比较。先看一下str2的值, 看一下sub_4110BE函数,
void *__cdecl sub_4110BE(char *a1, unsigned int a2, int *a3)
{
int v4; // [esp+D4h] [ebp-38h]
int v5; // [esp+D4h] [ebp-38h]
int v6; // [esp+D4h] [ebp-38h]
int v7; // [esp+D4h] [ebp-38h]
int i; // [esp+E0h] [ebp-2Ch]
unsigned int v9; // [esp+ECh] [ebp-20h]
int v10; // [esp+ECh] [ebp-20h]
int v11; // [esp+ECh] [ebp-20h]
void *v12; // [esp+F8h] [ebp-14h]
char *v13; // [esp+104h] [ebp-8h]
if ( !a1 || !a2 )
return 0;
v9 = a2 / 3;
if ( (int)(a2 / 3) % 3 )
++v9;
v10 = 4 * v9;
*a3 = v10;
v12 = malloc(v10 + 1);
if ( !v12 )
return 0;
j_memset(v12, 0, v10 + 1);
v13 = a1;
v11 = a2;
v4 = 0;
while ( v11 > 0 )
{
byte_41A144[2] = 0;
byte_41A144[1] = 0;
byte_41A144[0] = 0;
for ( i = 0; i < 3 && v11 >= 1; ++i )
{
byte_41A144[i] = *v13;
--v11;
++v13;
}
if ( !i )
break;
switch ( i )
{
case 1:
*((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v5 = v4 + 1;
*((_BYTE *)v12 + v5) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
*((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
v4 = v5 + 1;
break;
case 2:
*((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v6 = v4 + 1;
*((_BYTE *)v12 + v6) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
*((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[64];
v4 = v6 + 1;
break;
case 3:
*((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
v7 = v4 + 1;
*((_BYTE *)v12 + v7) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
*((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
*((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[byte_41A144[2] & 0x3F];
v4 = v7 + 1;
break;
}
}
*((_BYTE *)v12 + v4) = 0;
return v12;
}
看上去是base64加密,写个python解一下。
import base64
str = 'e3nifIH9b_C@n@dH'
flag = ''
for i in range(len(str)):
flag += chr(ord(str[i])-i)
print(base64.b64decode(flag))
2022-1-21
不一样的flag
下载下来是"不一样的flag.exe",扔到ExeinfoPE,未加壳,扔到IDA里,看一下伪代码,此处贴一下看的别人的伪代码分析, 说实话一开始没看明白,乱七八糟的,后来看了解析发现是个迷宫题,将49跟35转成值,发现是1跟#,大概想了一下,结尾是#,就输出正确,然后就看一下字符串是以#结尾,但是还是不知道是个啥,不过说起来做这种题,也从来没有想过直接打开xxx.exe,直接打开发现是可以操纵上下左右的,看了解析才知道是一个迷宫,将字符串分为5行5列(留个疑问,为什么是5行5列)。
*1111
01000
01010
00010
1111#
贴一下伪代码
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char v3[29]; // [esp+17h] [ebp-35h] BYREF
int v4; // [esp+34h] [ebp-18h]
int v5; // [esp+38h] [ebp-14h] BYREF
int i; // [esp+3Ch] [ebp-10h]
char v7[12]; // [esp+40h] [ebp-Ch] BYREF
__main();
v4 = 0;
strcpy(v3, "*11110100001010000101111#");
while ( 1 )
{
puts("you can choose one action to execute");
puts("1 up");
puts("2 down");
puts("3 left");
printf("4 right\n:");
scanf("%d", &v5);
if ( v5 == 2 )
{
++*(_DWORD *)&v3[25];
}
else if ( v5 > 2 )
{
if ( v5 == 3 )
{
--v4;
}
else
{
if ( v5 != 4 )
LABEL_13:
exit(1);
++v4;
}
}
else
{
if ( v5 != 1 )
goto LABEL_13;
--*(_DWORD *)&v3[25];
}
for ( i = 0; i <= 1; ++i )
{
if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
exit(1);
}
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 49 )
exit(1);
if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == 35 )
{
puts("\nok, the order you enter is the flag!");
exit(0);
}
}
}
*号为开头,只能走0,走1直接就退出,操纵的顺序即为flag,222441144222。
2022-1-22
SimpleRev
下载下来是SimpleRev,甩到IDA64里进行分析。直接F5, 发现输入d/D就可以进入,紧接着是一个Decry函数,我们对Decry函数进行分析
unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h]
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9; // [rsp+40h] [rbp-20h]
__int64 v10; // [rsp+48h] [rbp-18h]
int v11; // [rsp+50h] [rbp-10h]
unsigned __int64 v12; // [rsp+58h] [rbp-8h]
v12 = __readfsqword(0x28u);
*(_QWORD *)src = 0x534C43444ELL;
v7 = 0LL;
v8 = 0;
v9 = 0x776F646168LL; //数据在内存中是小端顺序,高位在高地址处,低位在低地址处
//故实际的字符顺序应为'0x4e44434c53'转为字符为'NDCLS'
v10 = 0LL;
v11 = 0;
text = join(key3, (const char *)&v9); // 让text等于key3+v9
// key3 = "kills"
// v9 = "hadow"
// 因为小端序存储
// 则text = "killshadow"
strcpy(key, key1); // 将key1复制给key
// key = "ADSFK"
strcat(key, src); // 将src处的字符串拼接到key后
// key = "ADSFKNDCLS"
v2 = 0;
v3 = 0;
getchar(); // 获取输入(清空缓冲区?)
v5 = strlen(key); // v5 = key的长度 v5 = 10
for ( i = 0; i < v5; ++i )
{
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )// if(key[v3]>64 && key[v3]<=90)
// key[v3] = key[v3]+32
// :将大写字母转换成小写字母
key[i] = key[v3 % v5] + 32; // key = "adsfkndcls"
++v3;
}
printf("Please input your flag:", src);
while ( 1 )
{
v1 = getchar();
if ( v1 == '\n' ) // 如果输入的为换行符,则退出
break;
if ( v1 == ' ' )
{
++v2; // 如果输入的为空格,则v2加一
}
else
{
if ( v1 <= 96 || v1 > 122 ) // 如果输入的v1不为小写字母
{
if ( v1 > 64 && v1 <= 90 ) // 如果v1为大写字母
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;// 对str2[v2]进行处理(v2为0每次加1)
// str2[v2] = (v1-key[v3]+58)%26 + 97
// 变换后str2[v2]存放小写字母
}
else
{ // 如果输入的值v1为小写字母
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;// 做同样处理
} // 如果不为大小写字母,则不进行处理
if ( !(v3 % v5) ) // 如果循环到key的最后一位
putchar(' '); // 打印处一个空格
++v2;
}
}
if ( !strcmp(text, str2) ) // 如果text和str2存储的相同,则成功
// text = "killshadow"
puts("Congratulation!\n");
else
puts("Try again!\n");
return __readfsqword(0x28u) ^ v12;
}
其中在处理text时,有一个函数为join,即text = join
&v9);,我们去查看一下
char *__fastcall join(const char *a1, const char *a2)
{
size_t v2; // rbx
size_t v3; // rax
char *dest; // [rsp+18h] [rbp-18h]
v2 = strlen(a1); //v2为a1的长度,即key的长度
v3 = strlen(a2); //v3为a2的长度,即v9的长度
dest = (char *)malloc(v2 + v3 + 1); //动态分配一个能存下key3和v9的空间dest
if ( !dest )
exit(1);
strcpy(dest, a1); //将a1的值赋给dest
strcat(dest, a2); //将a2的值拼接到dest
return dest; //实则返回a1+a2,即key+v9
}
其中对于str2做的处理为
str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
所以我们要做的就是对于str2进行逆向处理,写出脚本
#第一种 逆推
text = 'killshadow' # str2
key = 'adsfkndcls'
v3 = 0
v5 = len(key)
n = 0
flag = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in range(0, 10):
for j in range(0, 10):
v1 = (ord(text[j])-97)+26*i+ord(key[v3 % v5])-58
if(65 < v1 <= 90) or (v1 >= 97 and v5 <= 122):
flag[j] = chr(v1)
n = n+1
if n == 10:
print(''.join(flag))
break
v3 = v3 + 1
#第二种 暴力字典破解
text = 'killshadow' # str2
key = 'adsfkndcls'
v3 = 0
v5 = len(key)
dict1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
flag = ""
for i in range(0, 10):
n = 0
for char in dict1:
x = (ord(char) - 39 - ord(key[v3 % v5])+97) % 26 + 97
if chr(x) == text[i]:
n = n + 1
if n == 1:
print(char, end="")
v3 = v3 + 1
2022-1-23
[GXYCTF2019]luck_guy
下载下来是名为luck_guy的文件,扔到IDA里,直接F5,
int __cdecl main(int argc, const char **argv, const char **envp)
{
welcome(argc, argv, envp);
puts("_________________");
puts("try to patch me and find flag");
puts("please input a lucky number");
__isoc99_scanf("%d");
patch_me(0LL);
puts("OK,see you again");
return 0;
}
可以看到,存在一个patch_me的函数,跟踪
int __fastcall patch_me(int a1)
{
int result; // eax
if ( a1 % 2 == 1 )
result = puts("just finished");
else
result = get_flag();
return result;
}
肯定是get_flag
有用,跟踪
unsigned __int64 get_flag()
{
unsigned int v0; // eax
int i; // [rsp+4h] [rbp-3Ch]
int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h] BYREF
char v5; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]
v6 = __readfsqword(0x28u);
v0 = time(0LL); //得到时间
srand(v0); //使用时间作为种子生成随机数字
for ( i = 0; i <= 4; ++i )
{
switch ( rand() % 200 ) // 产生1-199之间的随机数
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char *)&s, f1);
strcat((char *)&s, &f2);
printf("%s", (const char *)&s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
s = 0x7F666F6067756369LL;
v5 = 0;
strcat(&f2, (const char *)&s);
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )
*(&f2 + j) -= 2;
else
--*(&f2 + j);
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
return __readfsqword(0x28u) ^ v6;
}