专栏名称: 吾爱破解论坛
吾爱破解论坛致力于软件安全与病毒分析的前沿,丰富的技术版块交相辉映,由无数热衷于软件加密解密及反病毒爱好者共同维护,留给世界一抹值得百年回眸的惊艳,沉淀百年来计算机应用之精华与优雅,任岁月流转,低调而奢华的技术交流与探索却
目录
相关文章推荐
掌中淄博  ·  突发公告!永久封禁 ·  昨天  
鹰潭市场监管  ·  政务服务便民热线四项国家标准正式实施 ·  2 天前  
搬砖小组  ·  超级公司,时代注脚 ·  3 天前  
搬砖小组  ·  超级公司,时代注脚 ·  3 天前  
安徽市场监管  ·  事关手机等数码产品和12类家电 补贴标准来了 ·  3 天前  
安徽市场监管  ·  事关手机等数码产品和12类家电 补贴标准来了 ·  3 天前  
51好读  ›  专栏  ›  吾爱破解论坛

【Android 原创】开心消消乐lua脚本解密

吾爱破解论坛  · 公众号  · 互联网安全  · 2017-05-27 17:32

正文

0x01 定位
开心消消乐lua的解析引擎在libhegame.so中,用IDA分析,发现很多函数并没有符号,包括所使用的OpenSSL和Lua的第三方库,增加了逆向的难度。
不过字符串并没有加密,可以通过查找".lua" "load" 这些字符串找到关键地方,通过字符串可以快速定位到加载lua文件的地方。


void __fastcall lua_load(int a1)

{

  int v1; // r0@1

  int v2; // r3@1

  int *v3; // r0@3

  int v4; // r0@3

  signed int v5; // r7@3

  int v6; // r0@4

  int v7; // r0@6

  int v8; // r5@6

  int v9; // r6@12

  int v10; // r5@12

  int v11; // r0@15

  int v12; // r4@15

  int v13; // r5@17

  int v14; // r4@18

  int v15; // r5@7

  int v16; // r0@30

  int v17; // r6@30

  int v18; // r0@30

  int v19; // r0@30

  int v20; // r0@30

  int v21; // r0@30

  int v22; // r0@30

  int v23; // r0@30

  int v24; // r0@30

  int v25; // r6@30

  int v26; // r0@30

  int v27; // r0@31

  int v28; // r0@31

  int *v29; // r0@33

  const char *v30; // r1@33

  int v31; // r0@16

  int buf; // [sp+8h] [bp-108h]@4

  int v33; // [sp+Ch] [bp-104h]@3

  int v34; // [sp+10h] [bp-100h]@1

  int v35; // [sp+1Ch] [bp-F4h]@1

  char v36; // [sp+20h] [bp-F0h]@2

  int v37; // [sp+24h] [bp-ECh]@3

  char v38; // [sp+28h] [bp-E8h]@3

  char v39; // [sp+2Ch] [bp-E4h]@3

  char v40; // [sp+30h] [bp-E0h]@3

  int v41; // [sp+34h] [bp-DCh]@3

  unsigned int len; // [sp+38h] [bp-D8h]@6

  int v43; // [sp+3Ch] [bp-D4h]@18

  int out; // [sp+40h] [bp-D0h]@3

  int v45; // [sp+44h] [bp-CCh]@1

  char v46; // [sp+48h] [bp-C8h]@32

 

  v34 = a1;

  v1 = sub_30E100();

  sub_30D100((int)&v35, v1, (int)&v45);

  v2 = sub_30D6B0(&v35, ".lua", 0);

  if ( v2 == *(_DWORD *)(v35 - 12) - 4 )

  {

    sub_30D610(&v36, &v35, 0, v2);

    sub_30D300(&v35, &v36);

    sub_30D130((int)&v36);

  }

  sub_30D100((int)&v38, (int)".", (int)&out);

  sub_30D100((int)&v39, (int)"/", (int)&v45);

  sub_7011C(&v40, &v35, &v38, &v39);

  v3 = (int *)sub_30D140(&v40, ".lua");

  v37 = *v3;

  *v3 = (int)&unk_3F3A68;

  sub_30D130((int)&v40);

  sub_30D130((int)&v39);

  sub_30D130((int)&v38);

  v4 = sub_74CD8(&v41, "src/", &v37);

  v33 = 2;

  v5 = 0;

  do

  {

    v6 = sub_1219BC(v4);

    buf = (*(int (**)(void))(*(_DWORD *)v6 + 16))();

    if ( buf )

    {

      v7 = sub_656EC();

      v8 = len;

      if ( v7 )

      {

        sub_74CD8(&v45, "@", &v37);

        v15 = sub_30E110(v34, buf, v8, v45);    // 读取lua文件

        sub_30D130((int)&v45);

        if ( v15 )

          v5 = 3;

      }

      else if ( len

{

        sub_68908("load_lua", "can not get enough file data of %s", v41);

        v5 = 5;

      }

      else

      {

        if ( !(dword_3E730C & 1) && sub_30D150(&dword_3E730C) )

        {

          byte_3E7310 = 0xE9u;

          byte_3E7311 = 0x74;

          byte_3E7313 = 0x92u;

          byte_3E7314 = 0xCCu;

          byte_3E7315 = 0x32;

          byte_3E7316 = 0x2E;

          byte_3E7319 = 0x2E;

          byte_3E731A = 0x7C;

          byte_3E731B = 0x34;

          byte_3E731C = 0x51;

          byte_3E731D = 0xD7u;

          byte_3E7312 = 0x7D;

          byte_3E7317 = 0x7D;

          byte_3E731E = 0xB3u;

          byte_3E7318 = 0x11;

          byte_3E731F = 0x6A;

          sub_30D160((int)&dword_3E730C);

        }

        v9 = len - 16;

        out = 0;

        v45 = 0;

        v10 = aes_cbc_decrypt((int)&byte_3E7310, buf, buf + 16, len - 16, &out);// 第一个参数为key aes解密 IV为文件开头的16个字节

        if ( v10 || (v10 = aes_cbc_decrypt((int)&byte_3E7310, buf, buf + 16, v9, &out)) != 0 )

        {

          zib_decompress(out, v10, (const void **)&v45);// 解压缩

          v12 = v11;

          if ( v11 || (zib_decompress(out, v10, (const void **)&v45), (v12 = v31) != 0) )

          {

            v13 = v45;

            if ( v12 > 3 && *(_BYTE *)v45 == 0xEF && *(_BYTE *)(v45 + 1) == 0xBB && *(_BYTE *)(v45 + 2) == 0xBF )

            {

              v13 = v45 + 3;

              v12 -= 3;

              sub_688EE("load_lua", "%s with utf-8 bom", v37);

            }

            sub_74CD8(&v43, "@", &v37);

            v14 = sub_30E110(v34, v13, v12, v43);

            sub_30D130((int)&v43);

            if ( v14 )

              v5 = 3;

          }

          else

          {

            v5 = 2;

          }

        }

        else

        {

          v5 = 1;

        }

        if ( v45 )

        {

          sub_30D490(v45);

          return;

        }

        if ( out )

          sub_30D490(out);

      }

      sub_30D490(buf);

      if ( !v5 )

        goto LABEL_44;

    }

    else

    {

      v4 = sub_68908("load_lua", "can not get file data of %s", v41);

      v5 = 4;

    }

    v33 = (v33 - 1) & 0xFF;

  }

  while ( v33 );

  if ( v5 )

  {

    v16 = sub_1219BC(v4);

    (*(void (__fastcall **)(int *, int, int))(*(_DWORD *)v16 + 28))(&v43, v16, v41);

    sub_30D6D0(&v45, 16);

    v17 = sub_30D690(&v45, "error loading module ");

    v18 = sub_30D790(v34, 1, 0);

    v19 = sub_30D690(v17, v18);

    v20 = sub_30D690(v19, " from file ");

    v21 = sub_30D690(v20, v43);

    v22 = sub_30D690(v21, ":\n\t");

    v23 = sub_30D690(v22, "fileSize:");

    v24 = sub_30E120(v23, len);

    v25 = sub_30D690(v24, "\n\tmessage: ");

    v26 = sub_30D790(v34, -1, 0);

    sub_30D690(v25, v26);

    switch ( v5 )

    {

      case 1:

      case 5:

        sub_30D690(&v45, ", decrypt error");

        v27 = sub_6CA3C(v43);

        v28 = sub_B1C10(v27);

        (*(void (**)(void))(*(_DWORD *)v28 + 12))();

        goto LABEL_32;

      case 2:

        v29 = &v45;

        v30 = ", uncompress error";

        break;

      case 3:

        v29 = &v45;

        v30 = ", load buff error";

        break;

      default:

        v29 = &v45;

        v30 = ", unknown error";

        break;

    }

    sub_30D690(v29, v30);

LABEL_32:

    sub_30D590(&out, &v46);

    sub_30E130(v34, out);

  }

LABEL_44:

  sub_30D130((int)&v41);

  sub_30D130((int)&v37);

  sub_30D130((int)&v35);

}


0x02 分析
调用的算法需要进行分析,原文件中并没有aes_cbc_decrypt和zib_decompress这两个符号,这是需要自己去分析函数功能,这个so调用了大量的第三方库的接口,加密算法也是调用
OpenSSL的,所以只要熟悉下这些库的接口,可以很方便确定加解密函数的功能和参数。


跟进aes_cbc_decrypt这个函数,有很明显的调试字符串,就可以马上确定所调用的是哪一个OpenSSL函数。(注:函数名称是加上去的)


很快的就能确定函数原型为aes_cbc_decrypt(char*key,char*iv,char*inbuf,int inlen,char**outbuf);
于是可以推出key和iv的来源,很明显key就是上面那一串密钥,注意2和3参数,相差16,于是可以推出来IV就是文件的开头16个字节
 
--------------------------------------------------------


跟进zib_decompress这个函数,1.2.8可以确定用了zlib的inflateInit(strm),第一个参数v15就是zib_decompress函数的第一个参数a1,也就是说aes解密完成
就直接开始解压,中间没进行额外的处理。


 
0x03 解密算法编写
从上面的分析可以知道,lua文件经过aes_cbc解密之后再进行解压,解密算法如下:


def decdata(c):

    key='\xe9\x74\x7d\x92\xcc\x32\x2e\x7d\x11\x2e\x7c\x34\x51\xd7\xb3\x6a'

    iv=c[0:16]

    main_data=c[16:]

    cryptor = AES.new(key,AES.MODE_CBC,iv) 

    pad_compress_data=cryptor.decrypt(main_data)

    str_len=len(pad_compress_data)

    pad=ord(pad_compress_data[-1])

    compress_data=pad_compress_data[0:str_len-pad]

    plain_text = zlib.decompress(compress_data)

    return plain_text


0x04 加密方案评价
1.编写程序的时候由于过多的留下调试字符串导致程序容易被逆向(要利用#define DEBUG控制代码编译,release版的程序不应该包含这些字符串)
2.过多的利用第三方开源加密库。开发者是比较喜欢使用别人造好的轮子,但是也给带来安全性问题。
3.从解密出来的lua来看,消消乐的lua脚本没经过编译,这就导致了源码泄露。


--官方论坛

www.52pojie.cn

--推荐给朋友

公众微信号:吾爱破解论坛

或搜微信号:pojie_52