首页
社区
课程
招聘
[原创]2017腾讯游戏安全技术竞赛 Round 1 标准及进阶题解分析
发表于: 2017-7-10 00:13 10472

[原创]2017腾讯游戏安全技术竞赛 Round 1 标准及进阶题解分析

2017-7-10 00:13
10472


为了学习死磕的精神,我也来做题。我选择了APK的题目,题目有两种难度,分别对应标准级别和进阶级别,标准级别是100分,进阶级别是200分。我先看的标准级别,然后看的进阶级别,由于自己对一些算法的熟练程度不够,逆向东西也逆得慢,所以花了不少时间。再说一点题外话,这个进阶题目和之前360移动安全竞赛的APK cm比较相似,都是RSA算法,name和RSA中的e 、n、 d参数绑定,不同之处是360的那道题目的难点在于用了ollvm来进行混淆,增大分析难度,而这一道题目的难点是需要写一个完整的注册机,这个是两道题的不同之处,好了不扯了,下面开始正题。
0x1REG_CHECK函数
Java层比较简单,只是一个reg_check函数,传入输入的key和code,然后进行验证。这个函数是整个程序的核心,reg_check函数如下:
int __fastcall CRegCheck::reg_check(int a1, int a2, _DWORD *a3, int a4)
{
  int v4; // r4@1
  char **v5; // r8@1
  int v6; // r6@1
  int v7; // r5@1
  int v8; // r0@2
  unsigned int v9; // r4@5
  int v10; // r4@5
  void *v11; // r4@6
  int v13; // [sp+20h] [bp-CD4h]@5
  void *ptr; // [sp+24h] [bp-CD0h]@2
  int v15; // [sp+28h] [bp-CCCh]@2
  int v16; // [sp+2Ch] [bp-CC8h]@2
  __int64 v17; // [sp+30h] [bp-CC4h]@2
  __int64 v18; // [sp+38h] [bp-CBCh]@7
  __int64 v19; // [sp+40h] [bp-CB4h]@7
  __int64 v20; // [sp+48h] [bp-CACh]@7
  __int64 v21; // [sp+58h] [bp-C9Ch]@5
  __int64 v22; // [sp+60h] [bp-C94h]@7
  int v23; // [sp+68h] [bp-C8Ch]@7
  int v24; // [sp+CE4h] [bp-10h]@1
 
  v4 = a4;
  v5 = (char **)a3;
  v6 = a2;
  v24 = _stack_chk_guard;
  v7 = 0;
  if ( CRegCheck::is_user_name_legal(_stack_chk_guard, (int *)a2) != 1 )
    goto LABEL_13;
  v8 = CRegCheck::get_formula_param(&v17, v6);
  ptr = 0;
  v15 = 0;
  v16 = 0;
  if ( v4 == 1 )
  {
    if ( !CBase64::base64_decode(*v5, (int)&ptr) )
      goto LABEL_8;
  }
  else
  {
    v9 = CRegCheck::get_rsa_key_seed(v8, v6);
    RSA::RSA((RSA *)&v21);
    RSA::RSAKey((RSA *)&v21, v9);
    sub_33440(&v13, (int *)v5);
    v10 = RSA::tdecrypto((int)&v21, (int)&v13, (int)&ptr);
    sub_332FC(v13 - 12);
    RSA::~RSA((RSA *)&v21);
    if ( !v10 )
    {
LABEL_8:
      v7 = 0;
      goto LABEL_9;
    }
  }
  v11 = ptr;
  if ( v15 - (_DWORD)ptr == 16 )
  {
    _aeabi_memclr(&v23, 0);
    _aeabi_memcpy(&v21, v11, 16);
    v7 = is_tangent(v20, v19, v18, v21, v22, v17);
LABEL_9:
    v11 = ptr;
    goto LABEL_11;
  }
  v7 = 0;
LABEL_11:
  if ( v11 )
    operator delete(v11);
LABEL_13:
  if ( _stack_chk_guard != v24 )
    _stack_chk_fail(_stack_chk_guard - v24);
  return v7;
}



在check函数的开端,遇见的是is_user_name_legal函数,它的作用是校验了一下name的长度是否是39位,格式需要如下:
xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx (一共39位,暂且称之为8个段,在之后用segment1~segment8来表示)
x需要在 ‘0’-‘9’ 、 ‘a’-‘f’之间,否则key的合法性就不予通过。



在get_formula_param函数中,根据输入的name 初始化了4个参数,每2个段生成一个参数,这些参数将在最后的is_tangent函数验证中用到。
具体参数代码如下:
a1 = 0;
a1 += (segment1[0] * segment8[0]) << 16 ;
a1 += segment1[1] ^ segment8[1];
a1 += segment1[2] % (segment8[2]+1)+ 1;
a1 += segment1[3] / (segment8[3]+1);
 
a2 =0;
a2 += (segment2[0] ^ segment7[0]) << 16 ;
a2 += (segment2[1] % (segment7[1]+3));
a2 += (segment2[2] / (segment7[2]+1)) + 5;
a2 += (segment2[3] + (segment7[3])) ;
a3 = 0;
a3 += (segment3[0] / (3 + segment6[0]) )<< 16 ;
a3 += (segment3[1] * segment6[1]);
a3 +=  segment3[2] %(segment6[2] + 7) +5;
a3 +=  segment3[3] + segment6[3];
a6 = 0;
a6 += (segment4[0] + segment5[0]) << 16;
a6 *= segment4[1]/(segment5[1]+2);
a6 += segment4[2] %(segment5[2] +5) +7;
a6 += segment4[3] * segment5[3];
好了,这就是最后校验用到的4个参数。


检查完输入key的合法性和初始化4个重要的参数之后,这个时候判断模式,判断做题的人是选择的什么难度,如果是选择标准难度,将会对输入的code进行base64解码,再进行计算,判断是否成功。我打算重点说说进阶难度题目的事情,所以这里就给出一组正确的key,其他的过程需要读者自行跟踪一下。
我算出来的一组key:
key:0234-5678-90ab-00ef-0f87-6543-21fe-0cba
code:A6Kf2FVPOOvERSOoIf@5l2==
如果是选择的进阶的题目,将会进入到另外一番天地,先贴一段代码,如下:
    v9 = CRegCheck::get_rsa_key_seed(v8, v6);
    RSA::RSA((RSA *)&v21);
    RSA::RSAKey((RSA *)&v21, v9);
    sub_33440(&v13, (int *)v5);
    v10 = RSA::tdecrypto((int)&v21, (int)&v13, (int)&ptr);
    sub_332FC(v13 - 12);
    RSA::~RSA((RSA *)&v21);
从这里可以看出来,进阶版这里用的是RSA算法对输入的key和code进行验证。



[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 2
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  CCkicker   +5.00 2017/07/18
最新回复 (22)
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
2

发文章有bug

2017-7-10 00:20
0
雪    币: 473
活跃值: (388)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
抛物线的切线
2017-7-10 09:48
0
雪    币: 82
活跃值: (104)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
rsa那里走到is_prime_san函数时校验p,q有可能出现和apk不同的情况,不知道楼主遇到没有
is_tangent函数还是和你之前的一样看x86的动态库就能明显看到两个公式,那两个公式是抛物线和切线关系的公式,函数名不是陷阱-  -
2017-7-10 09:57
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
5
RorschachL rsa那里走到is_prime_san函数时校验p,q有可能出现和apk不同的情况,不知道楼主遇到没有 is_tangent函数还是和你之前的一样看x86的动态库就能明显看到两个公式,那两个公式是抛 ...
谢谢楼上两位提醒,附上链接  816K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6W2L8W2)9J5k6i4N6A6K9$3W2H3k6h3c8A6j5g2)9J5k6h3!0J5k6#2)9J5c8Y4N6A6K9$3W2Q4x3V1k6b7j5i4u0S2j5X3!0D9j5b7`.`.
原来是抛物线的切线,高中数学
“rsa那里走到is_prime_san函数时校验p,q有可能出现和apk不同的情况”这句话没听懂,你是调的X86吗,这个我没看过,我调的是arm
2017-7-10 10:39
0
雪    币: 7187
活跃值: (5186)
能力值: ( LV10,RANK:163 )
在线值:
发帖
回帖
粉丝
6
楼主哪里来的符号文件  ~.~
2017-7-10 14:54
0
雪    币: 2183
活跃值: (1673)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
7
a3  +=  (segment3[1]  *  segment6[1]);
这个应该是
a3  ^=  (segment3[1]  *  segment6[1]);
2017-7-10 16:37
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
8
FraMeQ a3 += (segment3[1] * segment6[1]); 这个应该是 a3 ^= (segment3[1] * segment6[1]);
这个不影响,没问题的
2017-7-10 19:57
0
雪    币: 2579
活跃值: (1125)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
9

6666

2017-7-11 08:40
0
雪    币: 2579
活跃值: (1125)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
10
提醒一下A-F也可以,前面有个或0x20大写转小写,不知道考虑没
2017-7-11 08:50
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
11
loudy 提醒一下A-F也可以,前面有个或0x20大写转小写,不知道考虑没
谢谢提醒,自己调试的时候试过A-F,但是写文章忘了。。也能算  嘿嘿~谢谢指正
2017-7-11 09:41
0
雪    币: 8
活跃值: (38)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
12
膜大佬,逆了两天没发现是RSA,最后半爆破做的,可惜主办方不承认这种做法
2017-7-11 17:25
0
雪    币: 3
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
哈哈哈哈,当时也是在最后解大数一元二次方程组卡了,都想着自己手写了,发现python的numpy直接能解,高级语言就是好用
2017-7-11 19:28
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
14
echohello 膜大佬,逆了两天没发现是RSA,最后半爆破做的,可惜主办方不承认这种做法
  好奇怎么爆破的。。。
2017-7-11 22:55
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
15
userkeyharo 哈哈哈哈,当时也是在最后解大数一元二次方程组卡了,都想着自己手写了,发现python的numpy直接能解,高级语言就是好用[em_3]
看来要学习py了。。
2017-7-11 22:56
0
雪    币: 58782
活跃值: (21905)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
16
重新排了一下版
2017-7-12 22:04
0
雪    币: 339
活跃值: (1051)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
17
我是逆了看到算法是RSA,发现对算法不熟悉,又去补了一下RSA的算法,还是没解出来。楼主能不能指点下应该看什么资料,提升下对算法的熟悉。
2017-7-13 09:12
0
雪    币: 8
活跃值: (38)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
Ericky 好奇怎么爆破的。。。
emmm,他b64解密输入以后我看是生成了个链表,然后每个链表解密出一个char,我理解链表里控制生成的就三个char,每个大小0x31,于是我就注进去调他的函数爆了,就是慢了点。。。爆一个得5min左右~
2017-7-13 18:41
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
19
Loopher 我是逆了看到算法是RSA,发现对算法不熟悉,又去补了一下RSA的算法,还是没解出来。楼主能不能指点下应该看什么资料,提升下对算法的熟悉。
文章中有链接啊
2017-7-16 00:12
0
雪    币: 1185
活跃值: (458)
能力值: ( LV13,RANK:360 )
在线值:
发帖
回帖
粉丝
20
echohello emmm,他b64解密输入以后我看是生成了个链表,然后每个链表解密出一个char,我理解链表里控制生成的就三个char,每个大小0x31,于是我就注进去调他的函数爆了,就是慢了点。。。爆一个得5min ...
不是有300到400个char吗,就算只算爆破时间也得1500到2000分钟了啊  ,得几天。不过你能得出正确的key就已经很不错了
2017-7-16 00:15
0
雪    币: 8
活跃值: (38)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
21
Ericky 不是有300到400个char吗,就算只算爆破时间也得1500到2000分钟了啊 ,得几天。不过你能得出正确的key就已经很不错了
不是啊,你是说总密码长度400左右吧,但是程序里对比结果的时候只有16个char吧,每个char的生成是一毛一样的吧,所以只要针对一个char爆破就行了啊,对应起来就很小了吧
2017-7-17 14:35
0
雪    币: 184
活跃值: (96)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
22
好厉害的样子
2017-7-17 16:52
0
雪    币: 163
活跃值: (509)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
仿佛再次感受到当初被学霸所碾压的恐惧...
2017-7-25 19:05
0
游客
登录 | 注册 方可回帖
返回