hide—writeup

思路:

  1. 文件加了UPX壳,upx -d脱壳不成功,进行手动脱壳(dd命令将加载进内存的文件dump出来)
  2. dump出大量函数,利用strings <文件名> 寻找敏感字符串->定位函数->分析加密逻辑
  3. 编写逆向代码

参考文章:

  1. TEA、XTEA、XXTEA加密解密算法 https://blog.csdn.net/gsls200808/article/details/48243019
  1. strings hide 加入了UPX壳
    hide—writeup_第1张图片
  2. 手动脱壳,基本原理是程序在运行时会将代码释放到内存中,我们只需在运行时将内存中的可执行代码段dump出来即可
./hide
sudo dd if=/proc/$(pidof hidebak)/mem of=hide_dump1 skip=0x400000  bs=1c count=827392
sudo dd if=/proc/$(pidof hide)/mem of=hide_dump2 skip=7110656  bs=1c count=20480
cat hide_dump1 hide_dump2 > hide_dump
#$(pidof hidebak):进程号(ps -ef查看)
# if=文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >
# of=文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >
# ibs=bytes:一次读入bytes个字节,即指定一个块大小为bytes个字节。
    obs=bytes:一次输出bytes个字节,即指定一个块大小为bytes个字节。
    bs=bytes:同时设置读入/输出的块大小为bytes个字节。
# cbs=bytes:一次转换bytes个字节,即指定转换缓冲区大小。
# skip=blocks:从输入文件开头跳过blocks个块后再开始复制。
注意:通常只用当输出文件是磁盘或磁带时才有效,即备份到磁盘或磁带时才有效。
# count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。

hide—writeup_第2张图片

  1. shift+fn+f12 查看字符串列表
    hide—writeup_第3张图片
  2. 定位到sub_4009EF
    hide—writeup_第4张图片
  3. 加密函数逻辑
signed __int64 sub_4C8EF4()
{
  _BYTE *v0; // rdi
  __int64 *v1; // rsi
  unsigned __int64 v2; // rdx
  signed __int64 result; // rax

  if ( strlen(&unk_6CCDB0) == 21
    && *(&unk_6CCDB0 + 1) == 'w'
    && *(&unk_6CCDB0 + 2) == 'b'
    && *(&unk_6CCDB0 + 3) == '{'
    && *(&unk_6CCDB0 + 20) == '}' )
  {
    sub_4C8CC0(&unk_6CCDB4);           #共进行三轮加密
    sub_4C8E50(&unk_6CCDB4);
    sub_4C8CC0(&unk_6CCDB4);
    sub_4C8E50(&unk_6CCDB4);
    sub_4C8CC0(&unk_6CCDB4);
    v0 = &unk_6CCDB4;
    sub_4C8E50(&unk_6CCDB4);
    v1 = qword_4C8CB0;
    v2 = 0LL;
    while ( v2 < 0x10 && *v0 == *v1 )
    {
      ++v2;
      ++v0;
      v1 = (v1 + 1);
    }
  }
  __asm { syscall; LINUX - sys_write }
  result = 60LL;
  __asm { syscall; LINUX - sys_exit }
  return result;
}
  1. sub_4C8CC0和sub_4C8E50为一轮加密算法,经查阅,此算法是xtea算法
__int64 __fastcall sub_4C8CC0(__int64 a1)
{
  __int64 result; // rax
  unsigned __int64 v2; // rt1
  unsigned int v3; // [rsp+18h] [rbp-48h]
  __int64 v4; // [rsp+1Ch] [rbp-44h]
  signed int i; // [rsp+24h] [rbp-3Ch]
  signed int j; // [rsp+28h] [rbp-38h]
  int v7; // [rsp+40h] [rbp-20h]
  int v8; // [rsp+44h] [rbp-1Ch]
  int v9; // [rsp+48h] [rbp-18h]
  int v10; // [rsp+4Ch] [rbp-14h]
  unsigned __int64 v11; // [rsp+58h] [rbp-8h]

  v11 = __readfsqword(0x28u);
  v7 = 1883844979;
  v8 = 1165112144;
  v9 = 2035430262;
  v10 = 861484132;
  for ( i = 0; i <= 1; ++i )
  {
    v3 = *(8 * i + a1);
    v4 = *(a1 + 4 + 8 * i);
    for ( j = 0; j <= 7; ++j )
    {
      v3 += (*(&v7 + (BYTE4(v4) & 3)) + HIDWORD(v4)) ^ (((v4 >> 5) ^ 16 * v4) + v4);
      HIDWORD(v4) += 1735289196;
      LODWORD(v4) = ((*(&v7 + ((HIDWORD(v4) >> 11) & 3)) + HIDWORD(v4)) ^ (((v3 >> 5) ^ 16 * v3) + v3)) + v4;
    }
    *(a1 + 8 * i) = v3;
    *(a1 + 4 + 8 * i) = v4;
  }
  v2 = __readfsqword(0x28u);
  result = v2 ^ v11;
  if ( v2 != v11 )
    result = (loc_4C8B9A)();
  return result;
}
_BYTE *__fastcall sub_4C8E50(__int64 a1)
{
  _BYTE *result; // rax
  signed int i; // [rsp+14h] [rbp-4h]

  for ( i = 0; i <= 15; ++i )
  {
    result = (i + a1);
    *result ^= i;
  }
  return result;
}
  1. 逆向破解代码
/*sunyukun 31/5/2019*/
#include 
#include 
 /* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */
 void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0X676E696C;
    for (i=0; i < num_rounds; i++) {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}
 
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0X676E696C, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}
void xor1(uint32_t v[2]){
    uint32_t t[2];
    unsigned int i=0;
    t[0]=0;
    t[1]=0;
    for(i=0;i<4;i++){
        t[0]+=(((unsigned int)v[0]>>(8*i) & 0xff)^i)<<(8*i);
    }
    for(i=4;i<8;i++){
        t[1]+=(((unsigned int)v[1]>>(8*i) & 0xff)^i)<<(8*i);
    }
    v[0]=t[0];
    v[1]=t[1];
}
void xor2(uint32_t v[2]){
    uint32_t t[2];
    unsigned int i=8;
    t[0]=0;
    t[1]=0;
    for(;i<12;i++){
        t[0]+=(((unsigned int)v[0]>>(8*i) & 0xff)^i)<<(8*i);
    }
    for(;i<16;i++){
        t[1]+=(((unsigned int)v[1]>>(8*i) & 0xff)^i)<<(8*i);
    }
    v[0]=t[0];
    v[1]=t[1];
}
void getflag(uint32_t v[2],uint32_t v2[2]){
    unsigned int i=0;
    printf("qwb{");
    for(i=0;i<4;i++){
        printf("%c", (v[0]>>(8*i)&0xff));
    }
    for(i=0;i<4;i++){
        printf("%c", (v[1]>>(8*i)&0xff));
    }
    for(i=0;i<4;i++){
        printf("%c", (v2[0]>>(8*i)&0xff));
    }
    for(i=0;i<4;i++){
        printf("%c", (v2[1]>>(8*i)&0xff));
    }
    printf("}");
    printf("\n");
}
//c=[0x52 ,0xB8,0x13 ,0x7F ,0x35 ,0x8C ,0xF2 ,0x1B ,0xF4 ,0x63 ,0x86 ,0xD2 ,0x73 ,0x4F ,0x1E ,0x31]
int main()
{
    // uint32_t v[2]={0x7c11b952,0x1cf48931};
    uint32_t const k[4]={0x70493173,0x45723350,0x79523376,0x33593464};
    unsigned int r=8;//num_rounds建议取值为32
    uint32_t v[2]={0x7f13b852,0x1bf28c35};
    uint32_t v2[2]={0xd28663f4,0x311e4f73};
    //part one
    xor1(v);
    decipher(r, v, k);
    xor1(v);
    decipher(r, v, k);
    xor1(v);
    decipher(r, v, k);
    printf("解密后的低64位数据:0x%.8x 0x%.8x\n",v[0],v[1]);
    //part two
    xor2(v2);
    decipher(r, v2, k);
    xor2(v2);
    decipher(r, v2, k);
    xor2(v2);
    decipher(r, v2, k);
    printf("解密后的高64位数据:0x%.8x 0x%.8x\n",v2[0],v2[1]);
    getflag(v,v2);
    return 0;
}

运行结果
hide—writeup_第5张图片

你可能感兴趣的:(reverse)