BinCrack 发表于 2019-12-13 21:25:46

Affinic Debugger纯静态分析编写注册机

本帖最后由 BinCrack 于 2019-12-13 21:28 编辑

飘云阁全网首发,未经许可,禁止转载。双十二买了几本书,其中一本书提到了gdb调试器得GUI前端工具——AffinicDebugger。用惯了OD、IDA等可视化界面得调试器,实在受不了命令行方式调试的gdb。另一个问题是IDA不支持安卓调试中设置硬件断点,在修改内核标志后,gdb可以胜任设置硬件断点得工作。于是花了半下午时间纯静态分析这款商业软件得注册机制,在完全不运行软件的情况下,分析出软件注册逻辑,希望给不太了解IDA用法的朋友提供一点参考,起到抛砖引玉的作用。软件界面如下,更多软件介绍以及商业版(提供免费下载,正版授权七百人民币)下载链接请自行浏览官网http://www.affinic.com/?page_id=109直接将主程序拖入IDA,通过字符串可以很快定位到关键验证函数。
接下来自然关注v13变量,sub_4766D0函数返回字符串‘001’即可成功。如上图所示,而这个函数里面都是一堆偏移,因此需要借助IDA的结构体功能辅助我们静态分析,这里仅以一处代码为例。QDate::QDate(
      (QDate *)&v13,
      *(unsigned __int16 *)(v2 + 30),
      *(unsigned __int16 *)(v2 + 32),
      *(unsigned __int16 *)(v2 + 34));
因此偏移30处为year变量,32处为month变量,34处为day变量。以此类推,根据琐碎的上下文代码逻辑,我们可以还原出整个结构体,这里直接给出全部结构体。还原出结构体后,IDA的F5伪代码接近于源码,可以与上图未处理的对照,注释很清楚,就不过多解释了。接着是verifyDate函数,也没什么好分析的,从sn中指定位置逐个获取一个字符,最后用于日期以及上图true,false变量的设置。int __thiscall verifyDate(myStruc *this, int a2)
{
myStruc *v2; // ebx
char *v3; // esi
char *v4; // eax
char *v5; // eax
char v6; // cl
char *v7; // eax
char v8; // cl
char *v9; // eax
char v10; // cl
unsigned __int16 v11; // ax
char *v12; // eax
char v13; // cl
unsigned __int16 v14; // ax
char *v15; // eax
char v16; // cl
unsigned __int16 v17; // ax
unsigned int year_l; // ebp
char *v19; // eax
char v20; // cl
unsigned __int16 v21; // ax
unsigned int year_h; // edi
char v23; // al
__int16 true_; // ax
unsigned int day_h; // edx
char day_l; // si
unsigned int month_; // ecx
unsigned __int16 v29; //
char v30; //
char sn; //
int false_; //
unsigned int month__; //
unsigned int day_h_; //
int day_l_; //
int v36; //
int v37; //

v2 = this;
v3 = &this->sn;
v36 = 0;
QString::QString(&sn, &this->sn);
v4 = *v3;
v37 = 1;
if ( *(v4 + 1) == '0' )
{
    v5 = QString::at(&sn, &v30, 47);
    if ( *v5 <= 0xFFu )
    {
      v6 = *v5;
      if ( (*v5 - '0') <= 9u )
      {
      false_ = (v6 - '0');
LABEL_6:
      QString::remove(&sn, 47, 1);
      v7 = QString::at(&sn, &v30, 39);
      if ( *v7 <= 0xFFu )
      {
          v8 = *v7;
          if ( (*v7 - 48) <= 9u )
          {
            day_l_ = (v8 - '0');
LABEL_9:
            QString::remove(&sn, 39, 1);
            v9 = QString::at(&sn, &v30, 31);
            if ( *v9 <= 0xFFu )
            {
            v10 = *v9;
            if ( (*v9 - 48) <= 9u )
            {
                v11 = v10 - 48;
LABEL_12:
                day_h_ = v11;
                QString::remove(&sn, 31, 1);
                v12 = QString::at(&sn, &v30, 23);
                if ( *v12 <= 0xFFu )
                {
                  v13 = *v12;
                  if ( (*v12 - 48) <= 9u )
                  {
                  v14 = v13 - 48;
LABEL_15:
                  month__ = v14;
                  QString::remove(&sn, 23, 1);
                  v15 = QString::at(&sn, &v30, 15);
                  if ( *v15 <= 0xFFu )
                  {
                      v16 = *v15;
                      if ( (*v15 - 48) <= 9u )
                      {
                        v17 = v16 - '0';
LABEL_18:
                        year_l = v17;
                        QString::remove(&sn, 15, 1);
                        v19 = QString::at(&sn, &v30, 7);
                        if ( *v19 <= 0xFFu )
                        {
                        v20 = *v19;
                        if ( (*v19 - 48) <= 9u )
                        {
                            v21 = v20 - 48;
LABEL_21:
                            year_h = v21;
                            QString::remove(&sn, 7, 1);
                            QString::at(&sn, &v29, 0);
                            QString::remove(&sn, 0, 1);
                            v23 = v29;
                            if ( v29 <= 0xFFu )
                            {
                              if ( (v29 - 48) <= 9u )
                              {
                              true_ = v29 - 48;
                              goto LABEL_24;
                              }
                            }
                            else
                            {
                              v23 = 0;
                            }
                            true_ = v23 - '7';
LABEL_24:
                            day_h = day_h_;
                            day_l = day_l_;
                            v2->true = true_;
                            v2->false = false_;
                            month_ = month__;
                            v2->year = 16 * (year_h & 0xF) + 2010 + (year_l & 0xF);
                            v2->month = month_ & 0xF;
                            v2->day = (day_l & 0x1F) + 32 * (day_h & 0xF);
                            v2->field_26 = ((day_h >> 4) & 1)
                                       + ((month_ >> 3) & 2)
                                       + ((year_l >> 2) & 4)
                                       + ((year_h >> 1) & 8);
                            QString::QString(a2, &sn);
                            goto LABEL_25;
                        }
                        }
                        else
                        {
                        v20 = 0;
                        }
                        v21 = v20 - 55;
                        goto LABEL_21;
                      }
                  }
                  else
                  {
                      v16 = 0;
                  }
                  v17 = v16 - 55;
                  goto LABEL_18;
                  }
                }
                else
                {
                  v13 = 0;
                }
                v14 = v13 - 55;
                goto LABEL_15;
            }
            }
            else
            {
            v10 = 0;
            }
            v11 = v10 - 55;
            goto LABEL_12;
          }
      }
      else
      {
          v8 = 0;
      }
      day_l_ = (v8 - '7');
      goto LABEL_9;
      }
    }
    else
    {
      v6 = 0;
    }
    false_ = (v6 - 55);
    goto LABEL_6;
}
v2->true = 0;
QString::QString(a2, &sn);
LABEL_25:
v36 = 1;
LOBYTE(v37) = 0;
QString::~QString(&sn);
return a2;
}接着分析最后一个函数finalEncryptint __thiscall finalEncrypt(myStruc *this, int a2)
{
myStruc *v2; // ebp
QString *email; // ebx
int v4; // eax
QString *name; // edi
int v6; // eax
int v7; // eax
const struct QString *suc_001; // ebp
int v9; // eax
int v10; // eax
int v11; // eax
QString *v12; // eax
QString *v13; // eax
signed int cur; // edi
__int16 v15; // si
char *v16; // ebx
unsigned int tmp; // eax
char v18; // al
int v20; //
char v21; //
char totalStr; //
int v23; //
int v24; //
const struct QString *fail_DG; //
char v26; //
char v27; //
const struct QString *suc_001_; //
int v29; //
char v30; //
char v31; //
int v32; //

v2 = this;
v24 = a2;
v29 = a2;
v23 = 0;
QString::QString(&v21);
email = &v2->email;
v32 = 1;
v4 = QString::trimmed(&v2->email, &v20);
LOBYTE(v32) = 2;
QString::operator=(&v2->email, v4);
LOBYTE(v32) = 1;
QString::~QString(&v20);
name = &v2->name;
v6 = QString::trimmed(&v2->name, &v20);
LOBYTE(v32) = 3;
QString::operator=(&v2->name, v6);
LOBYTE(v32) = 1;
QString::~QString(&v20);
if ( *(v2->email + 4) && *(*name + 4) )
{
    fail_DG = &v2->DG;
    v7 = QString::left(&v2->DG, &v20, 2);
    LOBYTE(v32) = 4;
    QString::operator=(&v2->DG, v7);
    LOBYTE(v32) = 1;
    QString::~QString(&v20);
    suc_001 = &v2->succeed;
    suc_001_ = suc_001;
    v9 = QString::left(suc_001, &v20, 3);
    LOBYTE(v32) = 5;
    QString::operator=(suc_001, v9);
    LOBYTE(v32) = 1;
    QString::~QString(&v20);
    while ( *(*name + 4) < 25 )
      QString::append(name, name);            // 将name扩展至25个字符
    v10 = QString::left(name, &v20, 25);
    LOBYTE(v32) = 6;
    QString::operator=(name, v10);
    LOBYTE(v32) = 1;
    QString::~QString(&v20);
    while ( *(*email + 4) < 40 )
      QString::append(email, email);            // 将email扩展至40个字符
    v11 = QString::left(email, &v20, 40);
    LOBYTE(v32) = 7;
    QString::operator=(email, v11);
    LOBYTE(v32) = 1;
    QString::~QString(&v20);
    v12 = sub_E63F90(&v27, fail_DG, name);      // 字符串拼接函数,将第二、三个参数拼接
    LOBYTE(v32) = 8;
    v13 = sub_E63F90(&v26, v12, suc_001_);      // 字符串拼接
    LOBYTE(v32) = 9;
    sub_E63F90(&totalStr, v13, email);          // 字符串拼接
    LOBYTE(v32) = 11;
    QString::~QString(&v26);
    LOBYTE(v32) = 12;
    QString::~QString(&v27);
    cur = 0;
    do
    {
      v15 = *QString::at(&totalStr, &fail_DG, cur);// 最终拼成了totalStr,为DG+name+001+email
      v16 = &v30;
      tmp = ((v15 + *QString::at(&totalStr, &v20, &v30)) % 34);// (totalStr+totalStr)%34
      if ( tmp >= 10 )
      v18 = tmp + 55;
      else
      v18 = tmp + 48;
      ++cur;
      *v16 = v18;
    }
    while ( cur < 35 );
    v31 = 0;
    QString::operator=(&v21, v30);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 13;
    QString::insert(&v21, 30, &v20);            // 在指定位置插入‘-’
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 14;
    QString::insert(&v21, 25, &v20);
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 15;
    QString::insert(&v21, 20, &v20);
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 16;
    QString::insert(&v21, 15, &v20);
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 17;
    QString::insert(&v21, 10, &v20);
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    v20 = QString::fromAscii_helper("-", 1);
    LOBYTE(v32) = 18;
    QString::insert(&v21, 5, &v20);
    LOBYTE(v32) = 12;
    QString::~QString(&v20);
    QString::QString(v24, &v21);
    v23 = 1;
    LOBYTE(v32) = 1;
    QString::~QString(&totalStr);
}
else
{
    QString::QString(v24, &v21);
    v23 = 1;
}
LOBYTE(v32) = 0;
QString::~QString(&v21);
return v24;
}至此分析完毕,注册成功效果图。最后上注册机源代码# -*- coding: UTF-8 -*-
name='bin'*25
email='[email protected]'*40
totalStr = 'DG' + name[:25] + '001' + email[:40]
sn=[]
for i in range(35):
    tmp = (ord(totalStr) + ord(totalStr))%34
    if tmp>=10:
      sn.append(chr(tmp + 55))
    else:
      sn.append(chr(tmp + 48))
sn.insert(30,'-')
sn.insert(25,'-')
sn.insert(20,'-')
sn.insert(15,'-')
sn.insert(10,'-')
sn.insert(5,'-')
#固定到期时间
sn.insert(0,'1')
sn.insert(7,'4')
sn.insert(15,'>')
sn.insert(23,'8')
sn.insert(31,'0')
sn.insert(39,'8')
sn.insert(47,'0')
print "".join(sn)

不破不立 发表于 2019-12-13 21:40:43

收藏,学习

jingjing668888 发表于 2019-12-13 21:42:23

学习学习,感谢分享 {:hug:}

单小锋 发表于 2019-12-13 21:49:32

前来捧场哈哈

mantou 发表于 2019-12-13 22:50:59

看着这分析确实非常流利呀

jingjing668888 发表于 2019-12-13 23:09:55


学习学习,感谢分享 ,顶顶更健康

lhglhg 发表于 2019-12-14 11:31:59

感谢分享 ,顶顶更健康

brajna 发表于 2019-12-14 14:20:20

这个真是厉害,非常感谢

rsice88 发表于 2019-12-14 15:23:01

不明觉厉!飘云加油!

Phenix 发表于 2019-12-14 18:32:04

学习了,感谢分享!
页: [1] 2 3 4 5
查看完整版本: Affinic Debugger纯静态分析编写注册机