首页
社区
课程
招聘
[原创]BS272.exe
发表于: 2020-3-15 17:46 3472

[原创]BS272.exe

2020-3-15 17:46
3472
打开之后先运行,输入code以为是简单的F(A) = F(B) 模式的CreakMe,结果想简单了:

程序没有其他的保护方式,查看关键字符串:

一开始啥头绪没有,但是看到一个大数,同时程序运行起来的提示,原来考核RSA算法。
6D6F632E6D736131352E777777
A324F100182D501F6F6F78F397A3AA59641023D6A3DED8A4BF344F1E0FC71C188F4D

RSA的原理借鉴其他人的流程 https://www.cnblogs.com/stwzhong/p/3402735.html


下面看主程序:
int wmain()
{
  unsigned __int8 v0; // al
  const char *N; // edi
  unsigned int v2; // ebx
  void (*v3)(const char *, ...); // esi
  int v4; // edx
  unsigned int v5; // edi
  char v6; // cl
  unsigned __int8 v7; // al
  char *v8; // ebx
  unsigned int v9; // edi
  int result; // eax

  dword_448680 = 0;
  v0 = 65;
  N = "A324F100182D501F6F6F78F397A3AA59641023D6A3DED8A4BF344F1E0FC71C188F4D";// 乘积N
  do
  {                                             // 循环读入大数
    v2 = byte_4281B0[v0];
    sub_4019F0(&dword_448680, &dword_448680);
    sub_401940(&dword_448680, v2);
    v0 = (N++)[1];
  }
  while ( v0 );
  v3 = printf;
  printf("Please input username:");
  memset(byte_448EA0, 0, 10240u);
  sscanf("www.51asm.com", "%s", byte_448EA0);
  printf("%s\n", "www.51asm.com");
  sub_406230(byte_448EA0, strlen(byte_448EA0)); // 没有卵用
  printf("Please input vericode:");
  memset(byte_448EA0, 0, 0x2800u);
  scanf("%s", byte_448EA0);
  v4 = 0;
  v5 = strlen(byte_448EA0);
  if ( v5 )                                     // 控制输入字符
  {
    while ( 1 )
    {
      v6 = byte_448EA0[v4];
      if ( (v6 - '0') > 9u && (v6 - 'a') > 0x19u && (v6 - 'A') > 0x19u )
        break;
      if ( ++v4 >= v5 )
        goto LABEL_8;
    }
    printf("Invalid char found in input string");
    getch();
    result = 0;
  }
  else
  {
LABEL_8:
    v7 = byte_448EA0[0];                        // 此时是用户输入
    dword_448A90 = 0;
    if ( byte_448EA0[0] )                       // 循环读入数据
    {
      v8 = byte_448EA0;
      do
      {
        v9 = byte_4281B0[v7];
        sub_4019F0(&dword_448A90, &dword_448A90);
        sub_401940(&dword_448A90, v9);
        v7 = (v8++)[1];
      }
      while ( v7 );
      v3 = printf;
    }
    v3("\ninput accepted as:\n");
    Size = 10240;
    sub_406330(&dword_448C98, byte_448EA0);     // 字符串转ascii 6D6F632E6D736131352E777777
    v3("Username : %s\n", byte_448EA0);
    Size = 10240;
    sub_406330(&dword_448A90, byte_448EA0);
    v3("Vericode : %s\n", byte_448EA0);
    v3("\nverifying...\n");
    sub_403E30(&dword_448C98);                  // 求 mod  先传入 username  N
    sub_403E30(&dword_448A90);                  // 输入的code mod N
    if ( sub_401510() )
      v3("%s\n", &unk_448EB5);
    else
      v3("failed\n");
    getch();
    result = 0;
  }
  return result;
}
程序自定义了一个大数  N,然后sub_406330是ascii转int函数,动态调试就可以出结果,sub_403E30 传入转换之后的username 对其 MOD  N操作,结果不变。
这块看直接看伪代码看不出来,用od动态调试就能看到传入的参数和后面的操作:

关键判断函数是sub_401510
signed int sub_401510()
{
  signed int v0; // eax
  int v1; // esi
  int v2; // eax
  char v4_N; // [esp+10h] [ebp-830h]
  int v5_p; // [esp+428h] [ebp-418h]
  char v6; // [esp+42Ch] [ebp-414h]
  int v7; // [esp+630h] [ebp-210h]
  int v8; // [esp+634h] [ebp-20Ch]
  int v9; // [esp+638h] [ebp-208h]

  v0 = 1;
  v9 = 0;
  v8 = 17;
  v7 = 1;
  do
  {
    if ( *(&v8 + v0) )
      break;
    v7 = --v0;
  }
  while ( v0 >= 0 );
  v7 = v0 + 1;
  sub_4064D0(&v5_p, &v7);                       // username ^ 17    p
  v1 = 0;
  while ( 1 )
  {
    v2 = 0;
    dword_44888C[0] = 1;
    dword_448888[0] = 0;
    do
    {
      if ( dword_44888C[v2] )
        break;
      dword_448888[0] = --v2;
    }
    while ( v2 >= 0 );
    dword_448888[0] = v2 + 1;
    if ( !sub_405310(&dword_448680, &v4_N, 0) ) // 对输入用户名  初始化
      sub_401000(&v6, &dword_448A90, dword_448888, v5_p, &v4_N);// RSA解码
    Size = 10240;
    if ( dword_448888[0] )
    {
      sub_4062A0(dword_448888[0]);
    }
    else
    {
      memset(byte_448EA0, 0, 0x2800u);
      Size = 0;
    }
    if ( !strcmp("Happy Birthday Buddy", byte_448EA0) )// 解码之后和关键字符串比较
      break;
    sub_401940(&v5_p, 1u);
    if ( ++v1 >= 100 )
      return 0;
  }
  return 1;
}

硬着头皮大概可以理清楚,用户输入的code mod 17 作为RSA里面的 e 参与后面的解码 d  使用,e被保存在一个数组里面,动调可以看到:


解码到和字符串Happy Birthday Buddy 相等,就返回正确(卵提示信息都没有)。

所以整个流程应该是这样:
已知大数 N  = A324F100182D501F6F6F78F397A3AA59641023D6A3DED8A4BF344F1E0FC71C188F4D
已知用户名      "www.51asm.com"

用户名  转成整数  U = 6D6F632E6D736131352E777777
U ^ 7  mod N 作为后续解码的  e=9CA87DE3775787F7695F3F316E503600348AB6F58BEF375D0ED8F8BE84425FA7A6C3

目标解码数据  Happy Birthday Buddy\x0ok  明名为  DE = 6B6F007964647542207961646874726942207970706148

e一直到e+ 99之间, 一定存在一对 e, d  使得 code = DE ^ d MOD N (code是用户输入的)

p 和 q 可以用因式分解工具得到:
p= B89EB7E0C9A568202F38B169D9D7E27B93
q =E2389B3C140BE6423EE5EB9DB5DAC2559F

但是这个 e 是动的 ,一个个试, e +2 就能得到正确结果:
e  = 9CA87DE3775787F7695F3F316E503600348AB6F58BEF375D0ED8F8BE84425FA7A6C5
d   = 3AD75813052BC545DAC589519734FF0972200E8E31DFA08DE50D15CFA2667132E4E1 

这里附上RSATool使用方法:
https://www.40huo.cn/blog/rsa-tools.html

然后计算code =  274964845CCC8AAA8A0CD62B0971A23954F741240EEDD43A02F79DA2B7372D68C80C


注意:这里有个雷,就是比较字符串的地方有换行符\0, 然后设置成功提示符是ok(之前的wp有用),所以是多解,但是如果是其他的提示,可能匹配d有难度。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//