easy-UPX+

144次阅读
没有评论

easy-UPX+

老样子 程序加过壳 直接UPX -d

得到脱壳程序,丢进IDA

easy-UPX+

找到main

easy-UPX+

程序逻辑分析:

定义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

easy-UPX+

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}

正文完
 0
评论(没有评论)