新CrackMe160之141 - NTS Crackme5

OD载入程序, 搜索界面定位到成功关键词00401534,向上找到方法入口004014B0即为按钮事件入口,下好断点开始单步跟踪算法
004014F8处, 用这个正则表达式 %[^+]+%s 将注册码分成两段, 说明注册码中间有个+号
接下来0040150E和00401524两处结果为0都会跳到失败处, 所以这两个地方都是关键算法, 看IDA源码也一目了然:

int __thiscall sub_4014B0(CWnd *this)
{
  CWnd *v1; // esi@1
  int v2; // edi@1
  int result; // eax@1
  char v4; // [sp+8h] [bp-80h]@3
  char v5; // [sp+1Ch] [bp-6Ch]@3
  char v6; // [sp+30h] [bp-58h]@1
  char Src; // [sp+54h] [bp-34h]@1

  v1 = this;
  v2 = CWnd::GetDlgItemTextA(this, 1000, &v6, 32);
  result = CWnd::GetDlgItemTextA(v1, 1001, &Src, 40);
  if ( v2 > 6 && result > 32 )
  {
    sscanf(&Src, aS, &v4, &v5);
    result = sub_401320(&v6, &v4); //这里 0040150E
    if ( result )
    {
      result = sub_4013E0(&v6, &v5); //这里 00401524
      if ( result )
        result = CWnd::MessageBoxA(v1, aSerialIsCorrec, 0, 0); //成功了
    }
  }
  return result;
}

所以分别进这两个方法看看:

BOOL __cdecl sub_401320(int a1, const char *a2) //a1:用户名 a2:系列号前半段
{
  unsigned int v2; // ecx@1
  unsigned int v3; // edx@1
  int v4; // edi@1
  char i; // al@1
  int v6; // ecx@2
  int v7; // eax@2
  int v8; // esi@2
  char Dest; // [sp+Ch] [bp-14h]@3

  v2 = 0;
  v3 = 1;
  v4 = a1;
  for ( i = *(_BYTE *)a1; i; ++v4 )
  {
    v6 = (i ^ 0x32142001) + v2;
    v7 = v6 | v3 * i;
    v8 = v7;
    v2 = (v7 % 7u + 2) * v6;
    i = *(_BYTE *)(v4 + 1);
    v3 = v8 * (v2 % 5 + 3);
  }
  sprintf(&Dest, Format, v2, v3); //%08X-%08X
  return strcmp(&Dest, a2) == 0;
}

BOOL __cdecl sub_4013E0(int a1, const char *a2) //a1:用户名 a2:系列号后半段
{
  unsigned int v2; // ecx@1
  int v3; // ebx@1
  char v4; // al@1
  unsigned int v5; // esi@1
  unsigned int i; // edi@1
  int v7; // ecx@2
  unsigned int v8; // esi@2
  char Dest; // [sp+Ch] [bp-14h]@3

  v2 = 1;
  v3 = a1;
  v4 = *(_BYTE *)a1;
  v5 = 0;
  for ( i = 0; v4; v5 = i + v8 * (i % 0xB + 2) )
  {
    v7 = v2 * v4;
    v8 = v5 - (v4 | 0xF001F001);
    i += v7 + v8;
    v2 = i + (i % 7 + 3) * (v8 | v7);
    v4 = *(_BYTE *)(v3++ + 1);
  }
  sprintf(&Dest, Format, v5, v2); //%08X-%08X
  return strcmp(&Dest, a2) == 0;
}

由上面两个算法明显可得,由用户名计算得到两个串分别与系列号前后串对比, 代码很完整可直接引用
注册机如下:

#include <stdio.h>

void sub_401320(char *user);
void sub_4013E0(char *user);

int main() {
	char user[51] = {0}; 
	printf("用户名: ");
	scanf("%s", user); getchar(); 
	int len = sizeof(user);
	if(len < 7){
		printf("用户名7位以上");
		getchar(); return 0; 
	}
	printf("系列号: ");
	sub_401320(user);
	printf("+");
	sub_4013E0(user);
	
	getchar(); return 0;
}

void sub_401320(char *user)
{
  unsigned int v2=0, v3=1;
  int v4, v6, v7, v8;
  char i;

  v4 = *(int *)&user;
  for ( i = *user; i; ++v4 )
  {
    v6 = (i ^ 0x32142001) + v2;
    v7 = v6 | v3 * i;
    v8 = v7;
    v2 = (v7 % 7u + 2) * v6;
    i = *(char *)(v4 + 1);
    v3 = v8 * (v2 % 5 + 3);
  }
  printf("%08X-%08X", v2, v3);
}

void sub_4013E0(char *user)
{
  unsigned int i, v2=1, v5=0, v8;
  int v3, v7;
  char v4;

  v3 = *(int *)&user;
  v4 = *user;
  for ( i = 0; v4; v5 = i + v8 * (i % 0xB + 2) )
  {
    v7 = v2 * v4;
    v8 = v5 - (v4 | 0xF001F001);
    i += v7 + v8;
    v2 = i + (i % 7 + 3) * (v8 | v7);
    v4 = *(char *)(v3++ + 1);
  }
  printf("%08X-%08X", v5, v2);
}

运行示例:
用户名: Crackme5
系列号: 1600A8F8-DE196FF4+45990050-4AA47438

 
 
本节高手录制的视频,点击前往查看

 
 
 
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-12-30 14:35  hankerstudio  阅读(14)  评论(0)    收藏  举报