easy-UPX++
附件解压获得main.exe 检查一下有没有壳

Big sec. 02 [ FDSA ] , Don't try : upx.exe -d option ( min. 3.91 UPX required !!! )
魔改壳

直接打开010手动修改
成功脱壳


main逻辑分析
整型变量 v3 i
字符串型变量 v4
标准输入流 v5 v6
字符串型变量 encoded input
执行 _main() //可能是初始化
执行 patch_base64_chars_from_self() //不知道是什么 也没有参数传入 后续分析
初始化input
将输入的字符传入input
获取input的长度
将长度赋值给 v3
执行 base64_encode() 传入v3 并将结果赋值给 encoded
起循环 逐字符遍历过去 以 str的长度为界限 //str是什么?
v4赋值为 加密过后的第i位
进行判断 v4是否和 str[i]相等
如果错误就停止执行
输出正确
综上 也是一个flag校验程序
void __cdecl patch_base64_chars_from_self() //从程序自身获取base64加密表
{
std::ostream *v0; // rax
std::ostream *v1; // rax
std::ostream *v2; // rax
std::ostream *v3; // rax
_BYTE *v4; // rdx
_BYTE *v5; // rdx
_BYTE *v6; // rdx
__int64 v7; // [rsp+0h] [rbp-80h] BYREF
char buffer[272]; // [rsp+20h] [rbp-60h] BYREF
_BYTE v9[208]; // [rsp+130h] [rbp+B0h] BYREF
_BYTE v10[272]; // [rsp+200h] [rbp+180h] BYREF
std::fpos<int> v11; // [rsp+310h] [rbp+290h] BYREF
char *bytecode; // [rsp+320h] [rbp+2A0h]
std::streamsize size; // [rsp+328h] [rbp+2A8h]
int i_1; // [rsp+334h] [rbp+2B4h]
int i_0; // [rsp+338h] [rbp+2B8h]
int i; // [rsp+33Ch] [rbp+2BCh]
GetModuleFileNameA(0LL, (LPSTR)&v7 + 32, 0x104u); //读取文件
std::ifstream::basic_ifstream(v9, buffer, 4LL); //打开文件
if ( (unsigned __int8)std::ios::operator!(v10) )
{
v0 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cerr, "ERROR:OPEN ");
v1 = (std::ostream *)std::operator<<<std::char_traits<char>>(v0, buffer);
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v1);
}
else
{
std::istream::seekg(v9, 0LL, std::_Ios_Seekdir::_S_end);
std::istream::tellg(&v11);
size = std::fpos<int>::operator long long(&v11);
std::istream::seekg(v9, 0LL, std::_Ios_Seekdir::_S_beg);
bytecode = (char *)operator new[](size, refptr__ZSt7nothrow);
if ( bytecode )
{
std::istream::read(v9, bytecode, size);
if ( (unsigned __int8)std::ios::operator!(v10) )
{
v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cerr, "ERROR:READ");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
if ( bytecode )
operator delete[](bytecode);
}
else
{
for ( i = 0; i <= 3; ++i )
{
v4 = (_BYTE *)std::string::operator[](&base64_chars, i);
*v4 = bytecode[i + 392]; //替换ABCD 为392-395的字符
}
for ( i_0 = 0; i_0 <= 3; ++i_0 )
{
v5 = (_BYTE *)std::string::operator[](&base64_chars, i_0 + 10);
*v5 = bytecode[i_0 + 432]; //替换KLMN 为 432-435的字符
}
for ( i_1 = 0; i_1 <= 3; ++i_1 )
{
v6 = (_BYTE *)std::string::operator[](&base64_chars, i_1 + 19);
*v6 = bytecode[i_1 + 472]; //替换TUVW 为 472-475的字符
}
if ( bytecode )
operator delete[](bytecode);
}
std::ifstream::close(v9);
}
else
{
v2 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cerr, "ERROR:ALLOC");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v2);
std::ifstream::close(v9);
}
}
std::ifstream::~ifstream(v9);
}


获取到的字符串大概率是初始化的加密表
with open("main2.exe", "rb") as f:
data = f.read()
base64_table = list("QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm0123456789+/")
# 替换规则
for i in range(4):
base64_table[i] = chr(data[392 + i])
base64_table[10 + i] = chr(data[432 + i])
base64_table[19 + i] = chr(data[472 + i])
print("".join(base64_table))
VCXZTYUIOPFDSAGHJKLREWQBNMqwertyuiopasdfghjklzxcvbnm0123456789+/
str的内容如下
.data:0000000000473010 str db 57h, 64h, 73h, 61h, 4Eh, 42h, 50h, 37h, 2 dup(57h)
.data:0000000000473010 ; DATA XREF: main+8A↑o
.data:0000000000473010 ; main+E0↑o
.data:000000000047301A db 43h, 4Eh, 42h, 33h, 72h, 68h, 72h, 55h, 69h, 79h, 4Dh
.data:0000000000473025 db 70h, 4Bh, 6Bh, 53h, 33h, 30h, 3Dh, 0
payload
import base64
alt_b64 = "VCXZTYUIOPFDSAGHJKLREWQBNMqwertyuiopasdfghjklzxcvbnm0123456789+/"
std_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
dec_table = str.maketrans(alt_b64, std_b64)
ciphertext = "WdsaNBP7WWCNB3rhrUiyMpKkS30="
translated = ciphertext.translate(dec_table)
decoded = base64.b64decode(translated)
print("标准Base64串:", translated)
print("解码结果:", decoded)
正文完