1、茶:
1、经典查壳:
64位无壳软件:
2、ida启动:
main函数还是比较复杂的,他的流程大概就是输入flag,然后经过加密,在经过if语句判断与密文进行对比,我们使用ida的查询加密算法的插件来进行查询一下他的加密算法:
他给出的是salsa20加密,但是结果并不是这个加密算法,所以还是要靠自己的经验来观察
这个函数就是我们所要进行解密的函数,这个加密其实是chacha20加密,经过搜索可以得到chacha20加密他需要一个密钥key,一个偏移量ponce,,其中偏移量是一个12位的,但是他给的是16位,经过动调发现,他只取了前12位,下面给出解密代码(使用python的库进行解密,这个Crypto是真的难安装)
from Cryptodome.Cipher import ChaCha20
enc_data = bytes.fromhex("f568c48912eed6dc520c7164f44b6378e1d0d3e248914fa8847b405a131f")
key = b"SGludDogSW1wcm92ZSBvZiBTYWxzYTIw"
nonce = b"Is_This_"
cc = ChaCha20.new(key=key, nonce=nonce)
print(cc.decrypt(enc_data))
flag就是flag{But_I_Like_ChaCha20_More}
chacha20加密参考文章
[]: 【密码学】一文读懂ChaCha20-阿里云开发者社区
2、Pypl:
记录一下这个python逆向的解决
1、解包
1、首先可以观察到这个是一个python进行打包的程序
所以使用pyinstxtractor解包,我刚开始使用的是低于2.0的版本,这个解包出来的pyc不带后缀,而且也没有自动填补程序头
首先将所要解包的程序放在与其pyinstxtractor放在一起,然后打开终端运行
python pyinstxtractor.py 解包.exe (格式)
执行完毕会看到successful,而且会生成一个文件夹
上面的文件夹。就存放着我们解包的pyc文件,我们往他里去找根文件夹名字相同的文件,然后如果没有pyc的后缀,我们手动添加,最后拉入到010editor中进行查看文件头
如果缺少magic头,我们就应该重新修改,所以我们还是使用2.0以上的版本吧,方便快捷
此时我们可以通过一个dll文件进行查询他的python版本
所以这是一个python311的版本
贴一下各个版本的magic头
enum PycMagic {
MAGIC_1_0 = 0x00999902,
MAGIC_1_1 = 0x00999903, /* Also covers 1.2 */
MAGIC_1_3 = 0x0A0D2E89,
MAGIC_1_4 = 0x0A0D1704,
MAGIC_1_5 = 0x0A0D4E99,
MAGIC_1_6 = 0x0A0DC4FC,
MAGIC_2_0 = 0x0A0DC687,
MAGIC_2_1 = 0x0A0DEB2A,
MAGIC_2_2 = 0x0A0DED2D,
MAGIC_2_3 = 0x0A0DF23B,
MAGIC_2_4 = 0x0A0DF26D,
MAGIC_2_5 = 0x0A0DF2B3,
MAGIC_2_6 = 0x0A0DF2D1,
MAGIC_2_7 = 0x0A0DF303,
MAGIC_3_0 = 0x0A0D0C3A,
MAGIC_3_1 = 0x0A0D0C4E,
MAGIC_3_2 = 0x0A0D0C6C,
MAGIC_3_3 = 0x0A0D0C9E,
MAGIC_3_4 = 0x0A0D0CEE,
MAGIC_3_5 = 0x0A0D0D16,
MAGIC_3_5_3 = 0x0A0D0D17,
MAGIC_3_6 = 0x0A0D0D33,
MAGIC_3_7 = 0x0A0D0D42,
MAGIC_3_8 = 0x0A0D0D55,
MAGIC_3_9 = 0x0A0D0D61,
MAGIC_3_10 = 0x0A0D0D6F,
MAGIC_3_11 = 0x0A0D0DA7,
MAGIC_3_12 = 0x0A0D0DCB,
INVALID = 0,
};
https://blog.csdn.net/OrientalGlass/article/details/134612786
接下来就是准备将pyc反编译为python
2、反编译:
这里我尝试使用uncompyle6进行反编译,但是一直报错,我要不知道什么原因导致的,贴个图记录一下错误看看以后可以解决吗:
所以我还是使用在线网站将其反编译了
使用这个可以解决
得到代码:
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11
from Crypto.Util.number import bytes_to_long
def enc(key):
R = bytes_to_long(b'Welcome To PaluCTF!')
MOD = 2 ** 418
R = R ^ R - 60 >> 24
R = R ^ R - 60 << 88
R ^= key
R = -R ** 2 * 2024 % MOD
R = R * key % MOD
return R
flag = input('Welcome To PaluCTF!\nInput FLAG:')
m = bytes_to_long(flag.encode())
cor = 0x2E441F765514CCA89173554726494D37E9FBE774B6F807BC5F6E71117530CE3D7DB5F70554C03CD9055F4E42969600904DF1F4DB8L
if enc(m) == cor:
print('Congratulation!')
return None
print('Wrong FLAG!')
下面解决这个加密,设计异或和位运算所以使用这Z3对其进行解密
给一下代码:
from z3 import *
from Cryptodome.Util.number import *
def enc(key):
R = bytes_to_long(b"Welcome To PaluCTF!")
MOD = 2**418
R = R ^ ((R - 60) >> 24)
R = R ^ ((R - 60) << 88)
R ^= key
R = (-R * R * 2024) % MOD
R = (R * key) % MOD
return R
answer = 0x2E441F765514CCA89173554726494D37E9FBE774B6F807BC5F6E71117530CE3D7DB5F70554C03CD9055F4E42969600904DF1F4DB8
s=Solver()
key=BitVec('key',418)
s.add(enc(key)==answer)
s.check()
res=s.model()
#print(res)
flag=long_to_bytes(res[key].as_long())
print(flag)
所以得到flag,就是
3、O2:
1、经典查壳:
32位elf程序
2、IDA启动:
可以发现ELF的头文件报错了。所以我们找一个32位ELF文件修改一下
下面是正常的:
所以我们修改一下,将第五个01修改为02,意思是这是一个64位的程序
1:32位程序
2:64位程序
成功进入主函数
但是我的main函数不能反编译,显示编译错误,这个我没查出来是什么原因,网上教程说可以通过动调解决一下,就是找到出错的地址,然后F5反编译一下,然后返回就可以F5了
试了试果然可以
得到了主函数
__int64 __fastcall main(int a1, char **a2, char **a3)
{
__int64 v3; // rax
std::ostream *v4; // rbx
__int64 v5; // rax
_BYTE *v6; // rbp
char v7; // si
std::ostream *v8; // rax
__int64 v9; // rdx
size_t v10; // rbx
__int64 v11; // r13
__int64 v12; // rdx
__int64 v13; // rbx
__int64 v14; // rdx
__int64 (__fastcall *v16)(); // rax
_BYTE v17[32]; // [rsp+0h] [rbp-68h] BYREF
void *s1; // [rsp+20h] [rbp-48h] BYREF
size_t n; // [rsp+28h] [rbp-40h]v3 = std::operator<<<std::char_traits<char>>(&std::cout, "Hello! ", a3);
v4 = (std::ostream *)std::__ostream_insert<char,std::char_traits<char>>(v3, qword_607AF3F30340, qword_607AF3F30348);
v5 = *(_QWORD *)(*(_QWORD *)v4 - 24LL);
v6 = *(_BYTE **)((char *)v4 + v5 + 240);
if ( !v6 )
std::__throw_bad_cast();
if ( v6[56] )
{
v7 = v6[67];
}
else
{
std::ctype<char>::_M_widen_init(*(_QWORD *)((char *)v4 + v5 + 240));
v7 = 10;
v16 = *(__int64 (__fastcall **)())(*(_QWORD *)v6 + 48LL);
if ( v16 != std::ctype<char>::do_widen )
v7 = ((__int64 (__fastcall *)(_BYTE *, __int64))v16)(v6, 10LL);
}
v8 = (std::ostream *)std::ostream::put(v4, v7);
std::ostream::flush(v8);
std::operator<<<std::char_traits<char>>(&std::cout, "Check Flag:", v9);
std::operator>><char>(&std::cin, &unk_607AF3F30360);
sub_607AF3F2D5C0(v17, &unk_607AF3F30360, &qword_607AF3F30340);
sub_607AF3F2D6C0((__int64)&s1, (__int64)v17);
v10 = n;
v11 = qword_607AF3F30388;
v12 = qword_607AF3F30388;
if ( n <= qword_607AF3F30388 )
v12 = n;
if ( v12 && memcmp(s1, obj, v12) || (v13 = v10 - v11, v13 > 0x7FFFFFFF) || v13 < (__int64)0xFFFFFFFF80000000LL )
{
std::string::_M_dispose(&s1);
goto LABEL_14;
}
std::string::_M_dispose(&s1);
if ( (_DWORD)v13 )
{
LABEL_14:
std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!", v14);
goto LABEL_12;
}
std::operator<<<std::char_traits<char>>(&std::cout, "Right!", v14);
LABEL_12:
std::string::_M_dispose(v17);
return 0LL;
}
观察一下,我们可以发现 sub_607AF3F2D5C0(v17, &unk_607AF3F30360, &qword_607AF3F30340);这个就是加密函数
__int64 *__fastcall sub_607AF3F2D5C0(__int64 *a1, char **a2, _QWORD *a3)
{
__int64 *v3; // rcx
char *v4; // r12
__int64 v6; // r15
int v7; // ebp
__int64 v8; // rax
unsigned __int64 v9; // r13
unsigned __int64 v10; // rax
int v12; // [rsp+Ch] [rbp-4Ch]
char *v13; // [rsp+10h] [rbp-48h]v3 = a1 + 2;
*((_BYTE *)a1 + 16) = 0;
*a1 = (__int64)(a1 + 2);
v4 = *a2;
a1[1] = 0LL;
v13 = &a2[1][(_QWORD)v4];
if ( v4 != v13 )
{
v6 = 0LL;
v7 = 0;
while ( 1 )
{
v9 = v6 + 1;
v12 = (*v4 + *(char *)(*a3 + v7)) % 128;
v10 = a1 + 2 == v3 ? 15LL : a1[2];
if ( v10 < v9 )
{
std::string::_M_mutate(a1, v6, 0LL, 0LL, 1LL);
v3 = (__int64 *)*a1;
}
++v4;
*((_BYTE *)v3 + v6) = v12;
v8 = *a1;
a1[1] = v9;
*(_BYTE *)(v8 + v9) = 0;
v7 = (unsigned __int64)(v7 + 1) % a3[1];
if ( v13 == v4 )
break;
v6 = a1[1];
v3 = (__int64 *)*a1;
}
}
return a1;
}
v12 = (*v4 + *(char *)(*a3 + v7)) % 128;这一句就是主要的加密函数
可以简单分析一下各个变量的意思
v4就是我们输入的值,也就是flag(enc)
a3就是传入的key,我们可以找到他
也就是
v12=(enc[i]+key[i])%128
所以我们进行解密
enc=bytes.fromhex("364d4d5c3e387e00421c597a0a7302144d5b70087e064619567336297d151f56770a7935424f2a780643")
key=b'PaluCTF'
flag=''
for i in range(len(enc)):
flag+=chr((enc[i]-key[i%7])%128)
print(flag)
解释一下代码,方便下次自己使用
bytes.fromhex是将连续的两个数转换为hex
hex_string = '616263'
byte_array = bytearray.fromhex(hex_string)
print(byte_array)
bytearray(b'abc')
还有一种解法就是爆破,学习一下大佬的答案
from string import printable
enc = bytearray.fromhex("364d4d5c3e387e00421c597a0a7302144d5b70087e064619567336297d151f56770a7935424f2a780643")
key = "PaluCTF"
for i in range(len(enc)):
for c in printable:
if (ord(c) + ord(key[i % len(key)])) % 128 == enc[i]:
print(c, end="")
break
这里的from string import printable
# import string library function
import string
# Storing the sets of punctuation,
# digits, ascii_letters and whitespace
# in variable result
result = string.printable
# Printing the set of values
print(result)
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+, -./:;<=>?@[\]^_`{|}~
返回一系列可打印的值,所以我们使用双重循环进行爆破就ok了
答案是
flag{d80a0d76-23af-486e-a0bc-43a463eac552}
剩下两道不是很懂,再分析分析再写吧,帕鲁杯收获还是挺大的,对于加密算法也是又了解到一种