crackme.chm之aLoNg3x_1.exe

    点about按钮可以知道这个程序是让我们去掉按钮,让logo显示出来;首先用dede载入程序,看下有几个自定函数

    由于OK按钮是灰色的,所以我们先看下CancellaClick按钮函数,使用IDA特定标签库来解析

    使用F5分析函数

int __usercall TPrincipale_CancellaClick<eax>(int a1<eax>, int a2<ebx>)
{
  int v2; // ebx@1
  int v3; // ST00_4@1
  int v4; // edx@2
  unsigned int v6; // [sp-10h] [bp-14h]@1
  int (*v7)(); // [sp-Ch] [bp-10h]@1
  int (*v8)(); // [sp-8h] [bp-Ch]@1
  int v9; // [sp-4h] [bp-8h]@1
  int v10; // [sp+0h] [bp-4h]@1
  int v11; // [sp+4h] [bp+0h]@1

  v10 = 0;
  v9 = a2;
  v2 = a1;
  v8 = (int (*)())&v11;
  v7 = loc_442F32;
  v6 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v6);
  TControl::GetText(*(_DWORD *)(a1 + 736), &v10);
  v3 = sub_407670(v10);
  TControl::GetText(*(_DWORD *)(v2 + 732), &v10);
  if ( (unsigned __int8)sub_442AF4(v10, v3) )
  {
    sub_4231B0(*(_DWORD *)(v2 + 720), 0);
    LOBYTE(v4) = 1;
    (*(void (__fastcall **)(_DWORD, int))(**(_DWORD **)(v2 + 716) + 96))(*(_DWORD *)(v2 + 716), v4);
  }
  else
  {
    Controls::TControl::SetText(*(_DWORD *)(v2 + 736), &str_0_1[1]);
  }
  __writefsdword(0, v6);
  v8 = loc_442F39;
  return System::__linkproc___LStrClr(&v10);
}
    上面的代码简单分析后结果如下

int __usercall TPrincipale_CancellaClick<eax>(int this<eax>, int a2<ebx>)
{
  int this; // ebx@1
  int v3; // ST00_4@1
  int v4; // edx@2
  unsigned int v6; // [sp-10h] [bp-14h]@1
  int v9; // [sp-4h] [bp-8h]@1
  char *pszBuf;

  TControl::GetText(*(_DWORD *)(this + 736), &pszBuf);
  v3 = sub_407670(pszBuf);
  TControl::GetText(*(_DWORD *)(this + 732), &pszBuf);
  if (sub_442AF4(pszBuf, v3) )
  {
    sub_4231B0(*(_DWORD *)(this + 720), 0);
    LOBYTE(v4) = 1;
    (*(void (__fastcall **)(_DWORD, int))(**(_DWORD **)(this + 716) + 96))(*(_DWORD *)(this + 716), v4);
  }
  else
  {
    Controls::TControl::SetText(*(_DWORD *)(this + 736), &str_0_1[1]);
  }
}
    这边无法得知this+736/732对应的控件是什么,以及sub_407670函数的作用是什么,这边可以用OD调试下辅助我们分析

    可以看到第一次获取的是序列号

    这边0x4D2的十进制是1234,正好是我们输入的序列号的值,我们可以推测这个函数的功能应该就是StrToInt

    第二次获取的就是我们输入的用户名,现在我们已经知道sub_442AF4两个输入参数是什么了,分别是eax->用户名 edx->序列号值

    使用F5分析函数

int __fastcall sub_442AF4(int a1, int a2)
{
  int v2; // esi@2
  int v3; // ebx@2
  int v4; // eax@2
  signed int v5; // edx@3
  unsigned int v7; // [sp-Ch] [bp-1Ch]@1
  int (*v8)(); // [sp-8h] [bp-18h]@1
  int (*v9)(); // [sp-4h] [bp-14h]@1
  int v10; // [sp+8h] [bp-8h]@1
  int v11; // [sp+Ch] [bp-4h]@1
  int v12; // [sp+10h] [bp+0h]@1

  v10 = a2;
  v11 = a1;
  System::__linkproc___LStrAddRef();
  v9 = (int (*)())&v12;
  v8 = loc_442B90;
  v7 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v7);
  if ( sub_403A34(v11) > 5 )
  {
    v2 = sub_442A20(*(_BYTE *)(v11 + 4) % 7u + 2);
    v3 = 0;
    v4 = sub_403A34(v11);
    if ( v4 > 0 )
    {
      v5 = 1;
      do
      {
        v3 += v2 * *(_BYTE *)(v11 + v5++ - 1);
        --v4;
      }
      while ( v4 );
    }
  }
  __writefsdword(0, v7);
  v9 = loc_442B97;
  return System::__linkproc___LStrClr(&v11);
}
    函数初步分析结果如下,IDA的分析漏掉了最后的验证代码,即iResult – iSerial == 0x7a69


int __fastcall sub_442AF4(int szName, int iSerial)
{
  int iMagic; // esi@2
  int iResult; // ebx@2
  int iNLen; // eax@2
  int i; // edx@3
  int iSerial; // [sp+8h] [bp-8h]@1
  int szName; // [sp+Ch] [bp-4h]@1

  iSerial = iSerial;
  szName = szName;
  if ( strlen(szName) > 5 )
  {
    iMagic = sub_442A20(*(_BYTE *)(szName + 4) % 7u + 2);
    iResult = 0;
    iNLen = strlen(szName);
    if ( iNLen > 0 )
    {
      i = 1;
      do
      {
        iResult += iMagic * *(_BYTE *)(szName + i++ - 1);
        --iNLen;
      }
      while ( iNLen );
    }
  }
}
    计算iMagic的函数算法如下

int __fastcall sub_442A20(int a1)
{
  signed __int64 v1; // qax@2

  if ( a1 )
    v1 = a1 * (signed __int64)sub_442A20(a1 - 1);
  else
    LODWORD(v1) = 1;
  return v1;
}
    可以很容易看出,这就是一个递归函数,求的是n*(n-1)*...*1,所以CancellaClick按钮的伪代码以及注册算法如下:

#include <iostream>
using namespace std;

/*int __usercall TPrincipale_CancellaClick<eax>(int this<eax>, int iSerial<ebx>)
{
  int this; // ebx@1
  int v3; // ST00_4@1
  int v4; // edx@2
  unsigned int v6; // [sp-10h] [bp-14h]@1
  int v9; // [sp-4h] [bp-8h]@1
  char *pszBuf;

  TControl::GetText(*(_DWORD *)(this + 736), &pszBuf);
  v3 = sub_407670(pszBuf);
  TControl::GetText(*(_DWORD *)(this + 732), &pszBuf);
  if (sub_442AF4(pszBuf, v3) )
  {
    sub_4231B0(*(_DWORD *)(this + 720), 0);
    LOBYTE(v4) = 1;
    (*(void (__fastcall **)(_DWORD, int))(**(_DWORD **)(this + 716) + 96))(*(_DWORD *)(this + 716), v4);
  }
  else
  {
    Controls::TControl::SetText(*(_DWORD *)(this + 736), &str_0_1[1]);
  }
}*/

/*int __fastcall sub_442AF4(int szName, int iSerial)
{
  int iMagic; // esi@2
  int iResult; // ebx@2
  int iNLen; // eax@2
  int i; // edx@3
  int iSerial; // [sp+8h] [bp-8h]@1
  int szName; // [sp+Ch] [bp-4h]@1

  iSerial = iSerial;
  szName = szName;
  if ( strlen(szName) > 5 )
  {
    iMagic = sub_442A20(*(_BYTE *)(szName + 4) % 7u + 2);
    iResult = 0;
    iNLen = strlen(szName);
    if ( iNLen > 0 )
    {
      i = 1;
      do
      {
        iResult += iMagic * *(_BYTE *)(szName + i++ - 1);
        --iNLen;
      }
      while ( iNLen );
    }
  }
}*/

int NMul(int n)
{
	return n==1?1:n*NMul(n-1);
}

void main()
{
	char szName[] = "@@@@@@";
	int iSerial;
	int iMagicA = 0x7A69;
	int iMagicB = 0;
	int iTemp = 0;
	iMagicB = NMul(szName[4]%7+2);
	for (int i=0; i<6; i++)
		iTemp += iMagicB*szName[i];
	iSerial = iTemp - iMagicA;
	cout<<"The Serial:"<<iSerial<<endl;
}

    这样可以获到CancellaClick按钮的通关用户名和密码即”@@@@@@”和”-29033”,这个时候OK按钮被激活了,CancellaClick按钮消失了,下面我们来看下OK按钮对应的函数

int __usercall TPrincipale_OkClick<eax>(int a1<eax>, int a2<ebx>)
{
  int v2; // ebx@1
  int v3; // ST00_4@3
  unsigned int v5; // [sp-10h] [bp-14h]@1
  int (*v6)(); // [sp-Ch] [bp-10h]@1
  int (*v7)(); // [sp-8h] [bp-Ch]@1
  int v8; // [sp-4h] [bp-8h]@1
  int v9; // [sp+0h] [bp-4h]@1
  int v10; // [sp+4h] [bp+0h]@1

  v9 = 0;
  v8 = a2;
  v2 = a1;
  v7 = (int (*)())&v10;
  v6 = loc_442DED;
  v5 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v5);
  if ( *(_BYTE *)(*(_DWORD *)(a1 + 720) + 71) == 1 )
  {
    Controls::TControl::SetText(*(_DWORD *)(a1 + 736), &str_0_0[1]);
  }
  else
  {
    TControl::GetText(*(_DWORD *)(a1 + 736), &v9);
    v3 = sub_407670(v9);
    TControl::GetText(*(_DWORD *)(v2 + 732), &v9);
    if ( (unsigned __int8)sub_442BA0(v9, v3) )
      sub_4231B0(*(_DWORD *)(v2 + 716), 0);
  }
  __writefsdword(0, v5);
  v7 = loc_442DF4;
  return System::__linkproc___LStrClr(&v9);
}

    简单分析结果如下

int __usercall TPrincipale_OkClick<eax>(int this<eax>, int a2<ebx>)
{
  int this; // ebx@1
  int iSerial; // ST00_4@3
  int pszBuf; // [sp+0h] [bp-4h]@1

  if ( *(_BYTE *)(*(_DWORD *)(this + 720) + 71) == 1 )
  {
    Controls::TControl::SetText(*(_DWORD *)(this + 736), &str_0_0[1]);
  }
  else
  {
    TControl::GetText(*(_DWORD *)(this + 736), &pszBuf);
    iSerial = StrToInt(pszBuf);
    TControl::GetText(*(_DWORD *)(this + 732), &pszBuf);
    if ( (unsigned __int8)sub_442BA0(pszBuf, iSerial) )
      sub_4231B0(*(_DWORD *)(this + 716), 0);
  }
}

    我们会发现else这段和前面的CancellaClick的验证逻辑差不多,所以核心就是sub_442BA0这个函数,函数的输入参数为用户名和序列号值

int __usercall sub_442BA0<eax>(int a1<eax>, int a2<edx>, int a3<ebx>, int a4<esi>)
{
  int v4; // esi@1
  int v5; // esi@2
  int v6; // eax@3
  char v7; // zf@4
  unsigned int v9; // [sp-14h] [bp-20h]@1
  int (*v10)(); // [sp-10h] [bp-1Ch]@1
  int (*v11)(); // [sp-Ch] [bp-18h]@1
  int v12; // [sp-8h] [bp-14h]@1
  int v13; // [sp+0h] [bp-Ch]@1
  int v14; // [sp+4h] [bp-8h]@1
  int v15; // [sp+8h] [bp-4h]@1
  int v16; // [sp+Ch] [bp+0h]@1

  v14 = 0;
  v12 = a4;
  v4 = a2;
  v15 = a1;
  System::__linkproc___LStrAddRef(v12, a3, 0);
  v11 = (int (*)())&v16;
  v10 = loc_442C67;
  v9 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v9);
  Sysutils::IntToStr(v4, &v14);
  System::__linkproc___LStrLAsg(&v13);
  if ( sub_403A34(v14) > 5 )
  {
    v5 = sub_403A34(v14);
    if ( v5 >= 1 )
    {
      do
      {
        v6 = System::UniqueString(&v13);
        *(_BYTE *)(v6 + v5 - 1) = v5 * (signed __int16)(*(_BYTE *)(v14 + v5 - 1) * *(_BYTE *)(v14 + v5 - 1)) % 25 + 65;
        --v5;
      }
      while ( v5 );
    }
    System::__linkproc___LStrCmp(v13, v15);
    if ( v7 )
      System::__linkproc___LStrCmp(v15, v13);
  }
  __writefsdword(0, v9);
  v11 = loc_442C6E;
  return System::__linkproc___LStrArrayClr(&v13, 3);
}

    分析函数,得出伪代码以及注册算法如下

/*int __usercall sub_442BA0<eax>(int a1<eax>, int a2<edx>, int a3<ebx>, int a4<esi>)
{
  int iSerial; // esi@1
  int iSLen; // esi@2
  int pszBuf; // eax@3
  int pszTemp; // [sp+0h] [bp-Ch]@1
  int szSerial; // [sp+4h] [bp-8h]@1
  int pszName; // [sp+8h] [bp-4h]@1

  Sysutils::IntToStr(iSerial, &szSerial);
  if ( strlen(szSerial) > 5 )
  {
    iSLen = strlen(szSerial);
    if ( iSLen >= 1 )
    {
      do
      {
        pszBuf = System::UniqueString(&pszTemp);
        *(_BYTE *)(pszBuf + iSLen - 1) = iSLen * (signed __int16)(*(_BYTE *)(szSerial + iSLen - 1) * *(_BYTE *)(szSerial + iSLen - 1)) % 25 + 65;
        --iSLen;
      }
      while ( iSLen );
    }
    System::__linkproc___LStrCmp(pszTemp, pszName);
  }
}*/

void main()
{
	char szSerial[] = "111111";
	char szName[7] = {'\0'};
	for (int i=5; i>=0; i--)
		szName[i] = (i+1)*szSerial[i]*szSerial[i]%25+65;
	cout<<"The Name:"<<szName<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值