easy-UPX+
老样子 程序加过壳 直接UPX -d
得到脱壳程序,丢进IDA

找到main

程序逻辑分析:
定义104字节长度的enc [字符串]
整型变量 input_len 猜测是存储输入字符串长度的变量
执行 _main 函数 //似乎是初始化 不重要
执行read 并将数据放到enc里面 //猜测这个read 应该就是类似scanf的功能
input_len 变量赋值,存入长度
执行entrybuffer 传入enc以及input_len //猜测是对enc做了什么变换
进行判断 :执行check函数 判断返回值
check函数传入了三个值 enc Str input_len //其中Str应该已经写在字符串里面了
综上 应该是flag正确性判断
.data:0000000000473020 Str db 6Fh, 56h, 0C9h, 0E8h, 0DAh, 56h, 0F7h, 63h, 71h, 1Bh
.data:0000000000473020 ; DATA XREF: main+4E↑o
.data:000000000047302A db 48h, 44h, 0ECh, 0EDh, 2Ch, 0F6h, 19h, 0D7h, 0ACh, 7Ah
.data:0000000000473034 db 5Ah, 5Eh, 8Fh, 0CDh, 8Fh, 70h, 0FAh, 0Dh, 0E4h, 0F3h
.data:000000000047303E db 3Eh, 60h, 0D0h

EntryBuffer 函数分析
key = Real_Key
readSelfExeBytecode() //里面有对key的修改 上面那行代码是障眼法
执行 re4_crypt 即RC4加密运算 传入enc以及input_len 真正的key 0xAu (无符号十六进制 A 十进制 10)
在获取真正的key
bool __cdecl readSelfExeBytecode()
{
std::ostream *v0; // rax
std::ostream *v1; // rax
bool v2; // bl
std::ostream *v3; // rax
std::ostream *v4; // rax
__int64 v6; // [rsp+0h] [rbp-80h] BYREF
char buffer[272]; // [rsp+20h] [rbp-60h] BYREF
_BYTE v8[208]; // [rsp+130h] [rbp+B0h] BYREF
_BYTE v9[272]; // [rsp+200h] [rbp+180h] BYREF
std::fpos<int> v10; // [rsp+310h] [rbp+290h] BYREF
char *bytecode; // [rsp+328h] [rbp+2A8h]
std::streamsize size; // [rsp+330h] [rbp+2B0h]
std::streamsize i; // [rsp+338h] [rbp+2B8h]
GetModuleFileNameA(0LL, (LPSTR)&v6 + 32, 0x104u);
std::ifstream::basic_ifstream(v8, buffer, 4LL);
if ( (unsigned __int8)std::ios::operator!(v9) )
{
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);
v2 = 0;
}
else
{
std::istream::seekg((std::istream *)v8, 0LL, std::_Ios_Seekdir::_S_end);
std::istream::tellg((std::istream *)&v10);
size = std::fpos<int>::operator long long(&v10);
std::istream::seekg((std::istream *)v8, 0LL, std::_Ios_Seekdir::_S_beg);
bytecode = (char *)operator new[](size, refptr__ZSt7nothrow);
if ( bytecode )
{
std::istream::read((std::istream *)v8, bytecode, size);
if ( (unsigned __int8)std::ios::operator!(v9) )
{
v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cerr, "ERROR:READ");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v4);
if ( bytecode )
operator delete[](bytecode);
std::ifstream::close(v8);
v2 = 0;
}
else
{
for ( i = 512LL; i <= 519; ++i )
key[i - 512] = bytecode[i];
key[4] = 46; //连续取了八个字节的东西并且把key[4]写死成了.
if ( bytecode )
operator delete[](bytecode);
std::ifstream::close(v8);
v2 = 1;
}
}
else
{
v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cerr, "ERROR:DELIVER");
refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
std::ifstream::close(v8);
v2 = 0;
}
}
std::ifstream::~ifstream(v8);
return v2;
}
获取key
#使用脱壳之前的程序
with open("mainori.exe", "rb") as f:
f.seek(512)
key = bytearray(f.read(8))
print(key)
key[4] = ord('.') # 强制把第 5 位改成 '.'
print("Key (repr) =", repr(key)) # 打印完整的字节表示
print("Key (hex) =", key.hex()) # 打印16进制
print("Key (raw) =", key.decode(errors="replace")) # 尝试原样显示
结合动态调试 得到 4.24.UPX\x00\x00
rc4_crypt逻辑分析:
void __cdecl rc4_crypt(unsigned __int8 *data, unsigned int datalen, unsigned __int8 *key, unsigned int keylen)
{
__int64 v4; // [rsp+0h] [rbp-80h] BYREF
RC4_INFO rc4; // [rsp+20h] [rbp-60h]
unsigned __int8 tmp; // [rsp+22Fh] [rbp+1AFh]
int t; // [rsp+230h] [rbp+1B0h]
int j; // [rsp+234h] [rbp+1B4h]
int i; // [rsp+238h] [rbp+1B8h]
int dn; // [rsp+23Ch] [rbp+1BCh]
dn = 0;
i = 0;
j = 0;
t = 0;
rc4_init((PRC4_INFO)(&v4 + 4), key, keylen);
for ( dn = 0; dn < datalen; ++dn )
{
i = (i + 1) % 256;
j = (j + rc4.s_box[i]) % 256;
tmp = rc4.s_box[i];
rc4.s_box[i] = rc4.s_box[j];
rc4.s_box[j] = tmp;
t = (unsigned __int8)(rc4.s_box[i] + rc4.s_box[j]);
data[dn] += rc4.s_box[t]; //变种
}
}
void __cdecl rc4_init(PRC4_INFO prc4, unsigned __int8 *key, unsigned int keylen)
{
unsigned __int8 tmp; // [rsp+7h] [rbp-9h]
int j; // [rsp+8h] [rbp-8h]
int i; // [rsp+Ch] [rbp-4h]
int ia; // [rsp+Ch] [rbp-4h]
j = 0;
if ( prc4 )
{
for ( i = 0; i <= 255; ++i )
{
prc4->s_box[i] = -(char)i; //这里是倒着取出来的,需要注意
prc4->t_box[i] = key[i % keylen];
}
for ( ia = 0; ia <= 255; ++ia )
{
j = (prc4->s_box[ia] + j + prc4->t_box[ia]) % 256;
tmp = prc4->s_box[ia];
prc4->s_box[ia] = prc4->s_box[j];
prc4->s_box[j] = tmp;
}
}
}
payload
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
key = b"4.24.UPX\x00\x00"
cipher = bytes([
0x6F,0x56,0xC9,0xE8,0xDA,0x56,0xF7,0x63,0x71,0x1B,
0x48,0x44,0xEC,0xED,0x2C,0xF6,0x19,0xD7,0xAC,0x7A,
0x5A,0x5E,0x8F,0xCD,0x8F,0x70,0xFA,0x0D,0xE4,0xF3,
0x3E,0x60,0xD0
])
def rc4_init_variant(k):
s = [(256 - i) & 0xFF for i in range(256)] # <-- 改动点
t = [k[i % len(k)] for i in range(256)]
j = 0
for i in range(256):
j = (s[i] + j + t[i]) & 0xFF
s[i], s[j] = s[j], s[i]
return s
def rc4_decrypt_variant(data, key):
s = rc4_init_variant(key)
i = j = 0
out = bytearray()
for c in data:
i = (i + 1) & 0xFF
j = (j + s[i]) & 0xFF
s[i], s[j] = s[j], s[i]
t = (s[i] + s[j]) & 0xFF
out.append((c - s[t]) & 0xFF) # 加密时是+=, 解密时减
return bytes(out)
plain = rc4_decrypt_variant(cipher, key)
print(plain)
Vidar{UnveilPackedXtremeSecrets}
正文完