目录
题目:[ACTF新生赛2020]Universe_final_answer
日期:2023.5.11
题目:[ACTF新生赛2020]usualCrypt
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,将文件放入IDA中进行分析,找到main函数。查看main函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // esi
int v5[3]; // [esp+8h] [ebp-74h] BYREF
__int16 v6; // [esp+14h] [ebp-68h]
char v7; // [esp+16h] [ebp-66h]
char v8[100]; // [esp+18h] [ebp-64h] BYREF
sub_403CF8(&unk_40E140);
scanf("%s", v8);
memset(v5, 0, sizeof(v5));
v6 = 0;
v7 = 0;
sub_401080(v8, strlen(v8), v5);
v3 = 0;
while ( *(v5 + v3) == byte_40E0E4[v3] )
{
if ( ++v3 > strlen(v5) )
goto LABEL_6;
}
sub_403CF8(aError);
LABEL_6:
if ( v3 - 1 == strlen(byte_40E0E4) )
return sub_403CF8(aAreYouHappyYes);
else
return sub_403CF8(aAreYouHappyNo);
}
可以猜测sub_403CF8是输出函数,密文存放在byte_40E0E4中,查看sub_401080函数:
int __cdecl sub_401080(int a1, int a2, int a3)
{
int v3; // edi
int v4; // esi
int v5; // edx
int v6; // eax
int v7; // ecx
int v8; // esi
int v9; // esi
int v10; // esi
int v11; // esi
_BYTE *v12; // ecx
int v13; // esi
int v15; // [esp+18h] [ebp+8h]
v3 = 0;
v4 = 0;
sub_401000();
v5 = a2 % 3;
v6 = a1;
v7 = a2 - a2 % 3;
v15 = a2 % 3;
if ( v7 > 0 )
{
do
{
LOBYTE(v5) = *(a1 + v3);
v3 += 3;
v8 = v4 + 1;
*(v8 + a3 - 1) = aAbcdefghijklmn[(v5 >> 2) & 0x3F];
*(++v8 + a3 - 1) = aAbcdefghijklmn[16 * (*(a1 + v3 - 3) & 3) + ((*(a1 + v3 - 2) >> 4) & 0xF)];
*(++v8 + a3 - 1) = aAbcdefghijklmn[4 * (*(a1 + v3 - 2) & 0xF) + ((*(a1 + v3 - 1) >> 6) & 3)];
v5 = *(a1 + v3 - 1) & 0x3F;
v4 = v8 + 1;
*(v4 + a3 - 1) = aAbcdefghijklmn[v5];
}
while ( v3 < v7 );
v5 = v15;
}
if ( v5 == 1 )
{
LOBYTE(v7) = *(v3 + a1);
v9 = v4 + 1;
*(v9 + a3 - 1) = aAbcdefghijklmn[(v7 >> 2) & 0x3F];
v10 = v9 + 1;
*(v10 + a3 - 1) = aAbcdefghijklmn[16 * (*(v3 + a1) & 3)];
*(v10 + a3) = 61;
LABEL_8:
v13 = v10 + 1;
*(v13 + a3) = 61;
v4 = v13 + 1;
goto LABEL_9;
}
if ( v5 == 2 )
{
v11 = v4 + 1;
*(v11 + a3 - 1) = aAbcdefghijklmn[(*(v3 + a1) >> 2) & 0x3F];
v12 = (v3 + a1 + 1);
LOBYTE(v6) = *v12;
v10 = v11 + 1;
*(v10 + a3 - 1) = aAbcdefghijklmn[16 * (*(v3 + a1) & 3) + ((v6 >> 4) & 0xF)];
*(v10 + a3) = aAbcdefghijklmn[4 * (*v12 & 0xF)];
goto LABEL_8;
}
LABEL_9:
*(v4 + a3) = 0;
return sub_401030(a3);
}
将密文进行base64解密后,发现不是flag,猜测可能进行了换表。查看函数,发现在进行base64加密前,sub_401000函数对base64表进行了修改。
int sub_401000()
{
int result; // eax
char v1; // cl
for ( result = 6; result < 15; ++result )
{
v1 = aAbcdefghijklmn[result + 10];
aAbcdefghijklmn[result + 10] = aAbcdefghijklmn[result];
aAbcdefghijklmn[result] = v1;
}
return result;
}
通过动态调试来获取修改后的base64表,进行解密发现仍然是错误的,继续查看问题,发现在加密的末尾还有个sub_401030函数,查看函数发现是将密文的字母大小写进行了互换。
int __cdecl sub_401030(const char *a1)
{
__int64 v1; // rax
char v2; // al
v1 = 0i64;
if ( strlen(a1) )
{
do
{
v2 = a1[HIDWORD(v1)];
if ( v2 < 97 || v2 > 122 )
{
if ( v2 < 65 || v2 > 90 )
goto LABEL_9;
LOBYTE(v1) = v2 + 32;
}
else
{
LOBYTE(v1) = v2 - 32;
}
a1[HIDWORD(v1)] = v1;
LABEL_9:
LODWORD(v1) = 0;
++HIDWORD(v1);
}
while ( HIDWORD(v1) < strlen(a1) );
}
return v1;
}
思路理清后,完善解密脚本,脚本如下:
import base64
def main():
str1 = "zMXHz3TIgnxLxJhFAdtZn2fFk3lYCrtPC2l9"
str1 = str1.swapcase()
string1 = "ABCDEFQRSTUVWXYPGHIJKLMNOZabcdefghijklmnopqrstuvwxyz0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
if __name__ == '__main__':
main()
# b'flag{bAse64_h2s_a_Surprise}'
FLAG:flag{bAse64_h2s_a_Surprise}
日期:2023.5.13
题目:[MRCTF2020]Xor
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,32位,放入IDA中进行分析,找到main函数,但是无法将程序转成伪代码,因为程序很短,所以直接阅读汇编。
先将一段字符串压入栈中,再跳转进一个函数,猜测sub_2E1020是一个输出函数,而后面的sub_2E1050函数有一个"%s"参数,猜测是输入函数。
这一段指令对计算了一下输入的字符串长度,并与0x1b进行比较,这里可以知道输入长度为0x1b,也就是27。
"xor eax, eax"这里将eax寄存器清零,后面用al寄存器与cl进行异或,cl中存放的是输入内容,因为eax作为下标,可以判断是将输入值与其对应下标进行异或。最后再与byte_2FEA08中存放的密文进行比较。
由此理清思路后,即可写出解密脚本,脚本如下:
cipher = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g"
for i in range(len(cipher)):
print(chr(ord(cipher[i]) ^ i),end="")
# MRCTF{@_R3@1ly_E2_R3verse!}
FLAG:flag{@_R3@1ly_E2_R3verse!}
日期:2023.5.14
题目:Youngter-drive
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,通过查壳工具发现存在UPX壳。
对其进行脱壳后,放入IDA中进行分析,找到main函数。
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
HANDLE Thread; // [esp+D0h] [ebp-14h]
HANDLE hObject; // [esp+DCh] [ebp-8h]
sub_3610FF();
::hObject = CreateMutexW(0, 0, 0);
j_strcpy(Destination, Source);
hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
Thread = CreateThread(0, 0, sub_36119F, 0, 0, 0);
CloseHandle(hObject);
CloseHandle(Thread);
while ( dword_368008 != -1 )
;
sub_361190();
CloseHandle(::hObject);
return 0;
}
可以看出程序创建了两个线程来执行两个函数,查看StartAddress函数和sub_36119F函数下的sub_361B10函数。
void __stdcall __noreturn StartAddress_0(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_368008 > -1 )
{
sub_36112C(Source, dword_368008);
--dword_368008;
Sleep(0x64u);
}
ReleaseMutex(hObject);
}
}
void __stdcall __noreturn sub_361B10(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_368008 > -1 )
{
Sleep(0x64u);
--dword_368008;
}
ReleaseMutex(hObject);
}
}
先执行第一个线程,执行一次对输入的字符串第一个元素进行操作后休眠,再执行第二个线程对下一个元素进行操作后休眠,实际就是将输入的字符串下标为奇或偶时进行不同操作,于是可以写出下面的解密脚本:
cipher = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
dist = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
flag = ""
flag1 = []
for i in range(29):
if i % 2 == 1:
if ord(cipher[i]) >= ord('A') and ord(cipher[i]) <= ord('Z'):
flag += chr(dist.index(cipher[i])+96)
else:
flag += chr(dist.index(cipher[i])+38)
else:
flag += cipher[i]
print(flag)
# ThisisthreadofwindowshahaIsES
但是提交发现是错误的,而后看到其他师傅写的wp才知道,实际加密的是30个字符,检查时只检查了29个字符。那最后一个字符需要去猜一下。
FLAG:flag{ThisisthreadofwindowshahaIsESE}
日期:2023.5.15
题目:[MRCTF2020]hello_world_go
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,在IDA中打开,找到一个main_main函数,flag就在这里。
// main.main
void __cdecl main_main()
{
__int64 v0; // rcx
__int64 v1; // rax
__int64 v2; // rax
__int64 v3; // [rsp+20h] [rbp-90h]
__int64 v4; // [rsp+58h] [rbp-58h]
__int64 *v5; // [rsp+60h] [rbp-50h]
__int64 v6[2]; // [rsp+68h] [rbp-48h] BYREF
__int64 v7[2]; // [rsp+78h] [rbp-38h] BYREF
__int64 v8[2]; // [rsp+88h] [rbp-28h] BYREF
__int64 v9[2]; // [rsp+98h] [rbp-18h] BYREF
v5 = runtime_newobject(&RTYPE_string);
v9[0] = &RTYPE_string;
v9[1] = &off_4EA530;
fmt_Fprint(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v9, 1LL, 1LL);
v8[0] = &RTYPE__ptr_string;
v8[1] = v5;
fmt_Fscanf(&go_itab__ptr_os_File_comma_io_Reader, os_Stdin, "%s", 2LL, v8, 1LL, 1LL);
v0 = v5[1];
v1 = *v5;
if ( v0 != 24 )
goto LABEL_2;
v4 = *v5;
if ( !runtime_memequal("flag{hello_world_gogogo}", v1, 24LL) )
{
v1 = v4;
v0 = 24LL;
LABEL_2:
runtime_cmpstring("flag{hello_world_gogogo}", 24LL, v1, v0, v3);
if ( v3 >= 0 )
v2 = 1LL;
else
v2 = -1LL;
goto LABEL_4;
}
v2 = 0LL;
LABEL_4:
if ( v2 )
{
v6[0] = &RTYPE_string;
v6[1] = &off_4EA550;
fmt_Fprintln(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v6, 1LL, 1LL);
}
else
{
v7[0] = &RTYPE_string;
v7[1] = &off_4EA540;
fmt_Fprintln(&go_itab__ptr_os_File_comma_io_Writer, os_Stdout, v7, 1LL, 1LL);
}
}
FLAG:flag{hello_world_gogogo}
日期:2023.5.17
题目:[FlareOn4]IgniteMe
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,32位,无壳。
根据Description.txt可以知道flag的格式:
在IDA中找到一个sub_401050函数,这里对输入值进行了加密,并于密文进行了比较。
int sub_401050()
{
int v1; // [esp+0h] [ebp-Ch]
int i; // [esp+4h] [ebp-8h]
unsigned int j; // [esp+4h] [ebp-8h]
char v4; // [esp+Bh] [ebp-1h]
v1 = sub_401020(byte_403078);
v4 = sub_401000();
for ( i = v1 - 1; i >= 0; --i )
{
byte_403180[i] = v4 ^ byte_403078[i];
v4 = byte_403078[i];
}
for ( j = 0; j < 39; ++j )
{
if ( byte_403180[j] != byte_403000[j] )
return 0;
}
return 1;
}
在第一个for语句处下一个断点,可以知道v4的值为4,接着就可以写解密脚本:
cipher = [ 0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17, 0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48, 0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69]
key = 4
flag = ""
for i in range(len(cipher)-1,-1,-1):
cipher[i] = cipher[i] ^ key
key = cipher[i]
for j in range(len(cipher)):
print(chr(cipher[j]),end="")
# R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com
FLAG:flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}
日期:2023.5.18
题目:[GWCTF 2019]xxor
刷题平台:BUUCTF
方向:REVERSE
Write UP:
获取题目附件,64位,无壳。