编码喵
由于我水平有限,不知道这题为什么运行不了QAQ
直接IDA打开,main函数:
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // rax
__int64 v10; // rax
__int64 v11; // rbx
__int64 v12; // rax
__int64 v13; // rax
char v15[32]; // [rsp+20h] [rbp-80h] BYREF
char v16[32]; // [rsp+40h] [rbp-60h] BYREF
char v17[40]; // [rsp+60h] [rbp-40h] BYREF
char v18[8]; // [rsp+88h] [rbp-18h] BYREF
int v19; // [rsp+90h] [rbp-10h] BYREF
char v20; // [rsp+97h] [rbp-9h] BYREF
__int64 v21; // [rsp+98h] [rbp-8h]
_main(argc, argv, envp);
v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, " \n");
v4 = std::operator<<<std::char_traits<char>>(v3, "TJ TJTJ TJTJTJTJ TJTJTJ TJTJTJTJ TJTJTJTJ \n");
v5 = std::operator<<<std::char_traits<char>>(v4, "TJ TJ TJ TJ TJ TJ TJ \n");
v6 = std::operator<<<std::char_traits<char>>(v5, "TJ TJ TJ TJ TJ TJ \n");
v7 = std::operator<<<std::char_traits<char>>(v6, "TJ TJ TJ TJ TJ TJTJTJ \n");
v8 = std::operator<<<std::char_traits<char>>(v7, "TJ TJ TJ TJ TJ TJ \n");
v9 = std::operator<<<std::char_traits<char>>(v8, "TJ TJ TJ TJ TJ TJ TJ \n");
v10 = std::operator<<<std::char_traits<char>>(v9, "TJTJTJTJ TJTJ TJ TJTJTJ TJ TJ \n");
std::operator<<<std::char_traits<char>>(v10, " \n");
v19 = 1;
std::chrono::duration<long long,std::ratio<1ll,1ll>>::duration<int,void>(v18, &v19);
std::this_thread::sleep_for<long long,std::ratio<1ll,1ll>>(v18);
std::string::basic_string(v17);
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_4051A4);
std::getline<char,std::char_traits<char>,std::allocator<char>>(refptr__ZSt3cin, v17);
v11 = operator new(0x20ui64);
text_72(v11);
v21 = v11;
LODWORD(v11) = std::string::length(v17);
v12 = std::string::c_str(v17);
LitCTF_tanji_calculate::Encode[abi:cxx11](v16, v21, v12, v11);
std::allocator<char>::allocator(&v20);
std::string::basic_string(v15, "tgL0q1rgEZaZmdm0zwq4lweYzgeTngfHnI1ImMm5ltaXywnLowuYnJmWmx0=", &v20);
std::allocator<char>::~allocator(&v20);
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "探姬正在疯狂口算");
printProgress();
std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
if ( std::operator==<char>(v16, v15) )
v13 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_405208);
else
v13 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, &unk_40522D);
std::ostream::operator<<(v13, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "按 Enter 键退出...");
std::istream::get(refptr__ZSt3cin);
std::string::~string(v15);
std::string::~string(v16);
std::string::~string(v17);
return 0;
}
可以看见很明显的base系列字符串,进入Encode函数确定是base64编码,然后直接去解码发现不对,应该是换表了
找到base64编码表解密就可以了
import base64
import string
str1 = "tgL0q1rgEZaZmdm0zwq4lweYzgeTngfHnI1ImMm5ltaXywnLowuYnJmWmx0=" #待解秘字符串
string1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" #新表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))
#b'LitCTF{03034ed8-a2da-4aa6-b2c9-01ace9e26301}'
ezpython!!!!!
这题需要使用对应版本的python进行解包,否则无法解包出库文件导致解题出现困难
下载附件发现是python打包的exe文件,我们使用pyinstxtractor解包,这是一个github上的开源项目,各位可以自行搜索
我们使用其解包之后在线反编译
#!/usr/bin/env python
#visit https://tool.lu/pyc/ for more information
#Version: Python 3.11
import Litctfbase64
flag = input('flag:')
flag = Litctfbase64.b64decode(flag)
if flag == 'X=3o4hx=0EZwf=mMv13gX=3o4hx=qje2ZjtgZQmEKXZog4==':
print('win')
return None
print('no')
结果发现虽然是base64,但是它使用的不正常的base64库,我在解包出来的文件夹寻找了很久没有找到,后来才发现这是python3.11的文件,而我解包使用的却是3.12,我们切换版本重新解包就可以在PYZ-00.pyz_extracted文件夹找到Litctfbase64.pyc,反编译可以得到BASE64_ALPHABET = '8kuWYm=1JiUPs7DT4x+X5tcqZKfGvA0gFLB6y3QbV2rNOlRdMwnEohjzSe9/HIa-'
即新的base64编码表,正常解码就可以了
import base64
import string
str1 = "X=3o4hx=0EZwf=mMv13gX=3o4hx=qje2ZjtgZQmEKXZog4==" # 待解秘字符串
string1 = "8kuWYm=1JiUPs7DT4x+X5tcqZKfGvA0gFLB6y3QbV2rNOlRdMwnEohjzSe9/HIa-" # 新表
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))
#b'LitCTF{61happy_LitCTF_nice_base64}\x01\x86'
ezrc4
下载附件,IDA打开进main函数
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // esi
unsigned int v4; // eax
char Str[32]; // [rsp+20h] [rbp-168h] BYREF
__int64 Buf1[2]; // [rsp+40h] [rbp-148h] BYREF
int v8; // [rsp+50h] [rbp-138h]
char v9; // [rsp+54h] [rbp-134h]
char v10[296]; // [rsp+60h] [rbp-128h] BYREF
_main(argc, argv, envp);
IsDebuggerPresent_1();
Buf1[0] = 0x606EA290DC7CB2D5i64;
Buf1[1] = 0x3190B05971E41306i64;
v8 = -685914190;
v9 = 127;
printf(" ___ ___ \n");
printf(" ___ ___ / /\\ ___ / /\\ \n");
printf(" / /\\ / /\\ / /:/ / /\\ / /:/_ \n");
printf(" ___ ___ / /:/ / /:/ / /:/ / /:/ / /:/ /\\\n");
printf(" /__/\\ / /\\/__/::\\ / /:/ / /:/ ___ / /:/ / /:/ /:/\n");
printf(" \\ \\:\\ / /:/\\__\\/\\:\\__ / /::\\/__/:/ / /\\/ /::\\/__/:/ /:/ \n");
printf(" \\ \\:\\ /:/ \\ \\::/\\__/:/\\:\\ \\:\\ / /:/__/:/\\:\\ \\:\\/:/ \n");
printf(" \\ \\:\\/:/ \\__\\/\\__\\/ \\:\\ \\:\\ /:/\\__\\/ \\:\\ \\::/ \n");
printf(" \\ \\::/ /__/:/ \\ \\:\\ \\:\\/:/ \\ \\:\\ \\:\\ \n");
printf(" \\__\\/ \\__\\/ \\__\\/\\ \\::/ \\__\\/\\ \\:\\ \n");
printf(" \\__\\/ \\__\\/ \n");
printf("欢迎来到litctf,谢谢你的到来,下面题目就来咯\n");
printf(aCtf);
printf(aRc4);
printf(aRc4_0);
printf("input flag:");
scanf("%s21", Str);
v3 = strlen(Str);
v4 = strlen(key);
rc4_init(v10, key, v4);
rc4_crypt(v10, Str, v3);
if ( !memcmp(Buf1, Str, 0x15ui64) )
printf("win!!!!!!!!!!!!!!!!!!\n");
else
printf("nonono\n");
return 0;
}
题目说了是RC4,但是我没看见一些数据,给出了key为fenkey?
,想启动动调再看看的,结果一启动就闪退,发现主函数中有IsDebuggerPresent_1();反调试,于是我去外面把它nop掉,还是启动不了
发现还有一个函数main_0调用了反调试函数,然后我又进去nop了一大堆结果还是跑不起来,只能用另一种方法了
如果了解一些反调试的知识就可以知道,IsDebuggerPresent函数会直接读取PEB(Process Environment Block,进程环境块)中的BeingDebugged字段,然后通过jnz指令实现跳转,因此我们可以通过更改寄存器中的值使其不发生退出进程的跳转
这时将ZF寄存器的值改为1就可以走入左边的分支从而避免触发exit
再单步进反调试函数重复上述操作绕过反调试
其实不用绕过主函数中的这个反调试好像也可以写
我们就可以发现真正的key其实是litctf!
,这时再提出密文Buf1
hello_upx
题目名就叫upx,这题肯定考察的是upx壳,下载附件之后用upx工具发现脱壳失败,文件被修改了,于是打开010
需要修改下面的四个地方,出题人将大写的UPX改成了小写的(不知道我这里为什么U和u显示的都是乱码),我们将16进制字节码改成UPX对应的16进制ASCII就可以了
修改完之后用IDA打开,进去就是main函数
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v4[3]; // [rsp+20h] [rbp-50h]
__int16 v5; // [rsp+38h] [rbp-38h]
char v6[40]; // [rsp+40h] [rbp-30h] BYREF
int v7; // [rsp+68h] [rbp-8h]
int i; // [rsp+6Ch] [rbp-4h]
_main();
v4[0] = 0x707541504072684Ci64;
v4[1] = 0x655158612559632Bi64;
v4[2] = 0x4F5E4E601E5A4E20i64;
v5 = 101;
v7 = 1;
printf("welcome to LitCTF2024\nplease inputs you flag:");
scanf("%s", v6);
for ( i = 0; i <= 24; ++i )
v6[i] -= i;
for ( i = 0; i <= 24; ++i )
{
if ( *(v4 + i) != v6[i] )
v7 = 0;
}
if ( v7 )
printf(aGood);
else
printf("nononononno!");
return 0;
}
我们提取出v4的数据写脚本就可以得到flag
str = [0x4C, 0x68, 0x72, 0x40, 0x50, 0x41, 0x75, 0x70, 0x2B, 0x63,
0x59, 0x25, 0x61, 0x58, 0x51, 0x65, 0x20, 0x4E, 0x5A, 0x1E,
0x60, 0x4E, 0x5E, 0x4F, 0x65]
flag = ""
for i in range(25):
flag += chr(str[i] + i)
print(flag)
#LitCTF{w3lc0me_t0_l1tctf}